├── .github └── workflows │ └── flutter.yaml ├── .gitignore ├── .vscode └── launch.json ├── CHANGELOG.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── example ├── README.md ├── counter │ ├── .gitignore │ ├── .metadata │ ├── README.md │ ├── analysis_options.yaml │ ├── android │ │ ├── .gitignore │ │ ├── app │ │ │ ├── build.gradle │ │ │ └── src │ │ │ │ ├── debug │ │ │ │ └── AndroidManifest.xml │ │ │ │ ├── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ ├── kotlin │ │ │ │ │ └── com │ │ │ │ │ │ └── example │ │ │ │ │ │ └── counter │ │ │ │ │ │ └── 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 │ ├── linux │ │ ├── .gitignore │ │ ├── CMakeLists.txt │ │ ├── flutter │ │ │ ├── CMakeLists.txt │ │ │ ├── generated_plugin_registrant.cc │ │ │ ├── generated_plugin_registrant.h │ │ │ └── generated_plugins.cmake │ │ ├── main.cc │ │ ├── my_application.cc │ │ └── my_application.h │ ├── pubspec.yaml │ └── web │ │ ├── favicon.png │ │ ├── icons │ │ ├── Icon-192.png │ │ └── Icon-512.png │ │ ├── index.html │ │ └── manifest.json └── github_search │ ├── .gitignore │ ├── .metadata │ ├── README.md │ ├── analysis_options.yaml │ ├── android │ ├── .gitignore │ ├── app │ │ ├── build.gradle │ │ └── src │ │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ │ ├── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── kotlin │ │ │ │ └── com │ │ │ │ │ └── example │ │ │ │ │ └── github_search │ │ │ │ │ └── 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 │ ├── fonts │ ├── hind │ │ ├── DESCRIPTION.en_us.html │ │ ├── Hind-Bold.ttf │ │ ├── Hind-Light.ttf │ │ ├── Hind-Medium.ttf │ │ ├── Hind-Regular.ttf │ │ ├── Hind-Semibold.ttf │ │ ├── METADATA.json │ │ └── OFL.txt │ └── montserrat │ │ ├── DESCRIPTION.en_us.html │ │ ├── METADATA.json │ │ ├── Montserrat-Black.ttf │ │ ├── Montserrat-Bold.ttf │ │ ├── Montserrat-Light.ttf │ │ ├── Montserrat-Regular.ttf │ │ ├── Montserrat-Thin.ttf │ │ └── OFL.txt │ ├── 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 │ ├── github_client.dart │ ├── main.dart │ ├── search_actions.dart │ ├── search_empty_view.dart │ ├── search_epic.dart │ ├── search_error_view.dart │ ├── search_initial_view.dart │ ├── search_loading_view.dart │ ├── search_middleware.dart │ ├── search_reducer.dart │ ├── search_result.dart │ ├── search_result_view.dart │ ├── search_screen.dart │ └── search_state.dart │ ├── linux │ ├── .gitignore │ ├── CMakeLists.txt │ ├── flutter │ │ ├── CMakeLists.txt │ │ ├── generated_plugin_registrant.cc │ │ ├── generated_plugin_registrant.h │ │ └── generated_plugins.cmake │ ├── main.cc │ ├── my_application.cc │ └── my_application.h │ ├── pubspec.yaml │ └── web │ ├── favicon.png │ ├── icons │ ├── Icon-192.png │ └── Icon-512.png │ ├── index.html │ └── manifest.json ├── lib └── flutter_redux.dart ├── pubspec.yaml └── test └── flutter_redux_test.dart /.github/workflows/flutter.yaml: -------------------------------------------------------------------------------- 1 | name: Flutter 2 | on: 3 | pull_request: 4 | push: 5 | branches: 6 | - master 7 | jobs: 8 | test: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout Repository 12 | uses: actions/checkout@v3 13 | 14 | - name: Setup Flutter 15 | uses: subosito/flutter-action@v2 16 | with: 17 | channel: 'beta' 18 | 19 | - name: Recursive pub get 20 | run: find . -name 'pubspec.yaml' -execdir flutter pub get \; 21 | 22 | - name: Check formatting 23 | run: flutter format --set-exit-if-changed . 24 | 25 | - name: Run Analyzer 26 | run: flutter analyze . 27 | 28 | - name: Run Tests with Coverage 29 | run: flutter test --coverage --coverage-path=./lcov.info 30 | 31 | - name: Upload Coverage Report 32 | uses: codecov/codecov-action@v2 33 | with: 34 | files: ./lcov.info -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .atom/ 3 | .idea 4 | .packages 5 | .dart_tool/ 6 | .pub/ 7 | build/ 8 | ios/.generated/ 9 | packages 10 | pubspec.lock 11 | .flutter-plugins 12 | *.iml 13 | /coverage/ 14 | *.log 15 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Counter", 9 | "request": "launch", 10 | "type": "dart", 11 | "program": "example/counter/lib/main.dart" 12 | }, 13 | { 14 | "name": "Github Search", 15 | "request": "launch", 16 | "type": "dart", 17 | "program": "example/github_search/lib/main.dart" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.10.0 2 | 3 | * `onDidChange` now passed proper old and new value 4 | 5 | ## 0.10.0-beta.1 6 | 7 | * Remove deprecated null check against `WidgetsBinding.instance` 8 | 9 | ## 0.9.0 10 | 11 | * Throw Errors from onWillChange and onDidChange callbacks 12 | 13 | ## 0.8.2 14 | 15 | * Nullable ViewModels for callback functions as well as build 16 | 17 | ## 0.8.1 18 | 19 | * Support nullable ViewModels 20 | 21 | ## 0.8.0 22 | 23 | * Breaking Change: added null-safety 24 | * Breaking Change: updated to redux 5.0.0 25 | 26 | ## 0.7.0 27 | 28 | * Improved error messages in converters 29 | * Update InheritedWidget methods to latest version 30 | 31 | ## 0.6.0 32 | 33 | * Breaking Change: `onWillChange` now receives previous and new `ViewModel` 34 | * Breaking Change: Supports Redux 4.x - 5.0 35 | 36 | ## 0.5.4 37 | 38 | * Bugfix: Rebuilding the Widget will always rebuild with latest data 39 | * Enforce pedantic lint rules 40 | * Docs 41 | - Document all public members 42 | - Add more examples to README 43 | 44 | ## 0.5.3 45 | 46 | * Maintenance update 47 | * Remove dependency on test package, conflicts with latest Flutter 48 | * Update docs 49 | * Update example dependencies to latest versions 50 | * Apply stricter analysis options 51 | 52 | ## 0.5.2 53 | 54 | * Add `onDidChange` -- This callback will be run after the ViewModel has changed and the builder method is called 55 | * Add `onInitialBuild` -- This callback will be run after the builder method is called the first time 56 | 57 | ## 0.5.1 58 | 59 | * Add more advice to error message 60 | 61 | ## 0.5.0 62 | 63 | * Updated to work with latest version of Redux: 3.0.0 64 | 65 | ## 0.4.1 66 | 67 | * Update example to wrap entire app with StoreProvider 68 | * Throw more helpful error message if no StoreProvider is found in the tree 69 | 70 | ## 0.4.0 71 | 72 | * Works with Dart 2 (no longer supports Dart 1) 73 | * Stronger Type info Required 74 | * Breaking Changes: 75 | * `StoreProvider` now requires generic type info: `new StoreProvider` 76 | * `new StoreProvider.of(context).store` is now `StoreProvider.of(context)` 77 | 78 | ## 0.3.6 79 | 80 | * Add `onWillChange`. This function will be called before the builder and can be used for working with Imperative APIs, such as Navigator, TextEditingController, or TabController. 81 | 82 | ## 0.3.6 83 | 84 | * Add `onWillChange`. This function will be called before the builder and can be used for working with Imperative APIs, such as Navigator, TextEditingController, or TabController. 85 | 86 | ## 0.3.5 87 | 88 | * Bugfix: `onInit` was not called before the initial ViewModel is constructed. 89 | 90 | ## 0.3.4 91 | 92 | * Fix Changelog. 93 | 94 | ## 0.3.3 95 | 96 | * Optional `onDispose` function - The `StoreConnector` and `StoreBuilder` Widgets now accept an `onDispose` function that will be run when the Widget is removed from the Widget tree (using State.dispose under the hood). The `onDispose` function takes the Store as the first parameter, and can be used to dispatch actions that remove stale data from your State tree. 97 | * Move to github 98 | 99 | ## 0.3.2 100 | 101 | * Optional `onInit` function - The `StoreConnector` and `StoreBuilder` Widgets now accept an `onInit` function that will be run the first time the Widget is created (using State.initState under the hood). The `onInit` function takes the Store as the first parameter, and can be used to dispatch actions when your Widget is first starting up. This can be useful for data fetching. 102 | * `ignoreChange` function - `StoreConnector` now takes an advanced usage / optional function `ignoreChange`. It will be run on every store `onChange` event to determine whether or not the `ViewModel` and `Widget` should be rebuilt. This can be useful in some edge cases, such as displaying information that has been deleted from the store while it is animating off screen. 103 | * Documentation updates 104 | 105 | ## 0.3.1 106 | 107 | * Add the ability to build only once, while avoiding rebuilding on change. This can be handy if you need to manage access to the Store, but want to handle when to update your own Widgets. 108 | 109 | ## 0.3.0 110 | 111 | * Make `StoreProvider.of` a factory rather than a static method 112 | * Additional documentation based on questions from the community 113 | 114 | ## 0.2.0 115 | 116 | * Update for Redux 2.0.0 117 | 118 | ## 0.1.1 119 | 120 | * Update documentation 121 | 122 | ## 0.1.0 123 | 124 | Initial Version of the library. 125 | 126 | * Includes the ability to pass a Redux `Store` down to descendant Widgets using a `StoreProvider`. 127 | * Includes the `StoreConnector` and `StoreBuilder` Widgets that capture the `Store` from the `StoreProvider` and build a Widget in response. 128 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2017 Brian Egan 3 | 4 | Permission is hereby granted, free of charge, to any person 5 | obtaining a copy of this software and associated documentation 6 | files (the "Software"), to deal in the Software without restriction, 7 | including without limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of the Software, 9 | and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included 13 | in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 19 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 20 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 21 | USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # flutter_redux 2 | 3 | [![Build Status](https://travis-ci.org/brianegan/flutter_redux.svg?branch=master)](https://travis-ci.org/brianegan/flutter_redux) [![codecov](https://codecov.io/gh/brianegan/flutter_redux/branch/master/graph/badge.svg)](https://codecov.io/gh/brianegan/flutter_redux) 4 | 5 | A set of utilities that allow you to easily consume a 6 | [Redux](https://pub.dartlang.org/packages/redux) Store to build Flutter Widgets. 7 | 8 | This package supports null-safety and is built to work with 9 | [Redux.dart](https://pub.dartlang.org/packages/redux) 5.0.0+ and Flutter 3+. 10 | 11 | ## Redux Widgets 12 | 13 | * `StoreProvider` - The base Widget. It will pass the given Redux Store to all descendants that request it. 14 | * `StoreBuilder` - A descendant Widget that gets the Store from a `StoreProvider` and passes it to a Widget `builder` function. 15 | * `StoreConnector` - A descendant Widget that gets the Store from the nearest `StoreProvider` ancestor, converts the `Store` into a `ViewModel` with the given `converter` function, and passes the `ViewModel` to a `builder` function. Any time the Store emits a change event, the Widget will automatically be rebuilt. No need to manage subscriptions! 16 | 17 | ## Examples 18 | 19 | * [Simple example](https://github.com/brianegan/flutter_redux/tree/master/example/counter) - a port of the standard "Counter Button" example from Flutter 20 | * [Github Search](https://github.com/brianegan/flutter_redux/tree/master/example/github_search) - an example of how to search as a user types, demonstrating both the Middleware and Epic approaches. 21 | * [Todo app](https://github.com/brianegan/flutter_architecture_samples/tree/master/redux) - a more complete example, with persistence, routing, and nested state. 22 | * [Timy Messenger](https://github.com/janoodleFTW/timy-messenger) - large open source app that uses flutter_redux together with Firebase Firestore. 23 | 24 | ### Companion Libraries 25 | * [flipperkit_redux_middleware](https://pub.dartlang.org/packages/flipperkit_redux_middleware) - Redux Inspector (use [Flutter Debugger](https://github.com/blankapp/flutter-debugger)) for Flutter Redux apps 26 | * [flutter_redux_dev_tools](https://pub.dartlang.org/packages/flutter_redux_dev_tools) - Time Travel Dev Tools for Flutter Redux apps 27 | * [redux_persist](https://github.com/Cretezy/redux_persist) - Persist Redux State 28 | * [flutter_redux_navigation](https://github.com/flutterings/flutter_redux_navigation) - Use redux events for navigation 29 | * [flutter_redux_gen](https://marketplace.visualstudio.com/items?itemName=BalaDhruv.flutter-redux-gen) - VS Code Extension to generate redux code. 30 | 31 | ## Usage 32 | 33 | Let's demo the basic usage with the all-time favorite: A counter example! 34 | 35 | Note: This example requires flutter_redux 0.4.0+ and Dart 2! If you're using 36 | Dart 1, [see the old 37 | example](https://github.com/brianegan/flutter_redux/blob/eb4289795a5a70517686ccd1d161abdb8cc08af5/example/lib/main.dart). 38 | 39 | ```dart 40 | import 'package:flutter/material.dart'; 41 | import 'package:flutter_redux/flutter_redux.dart'; 42 | import 'package:redux/redux.dart'; 43 | 44 | // One simple action: Increment 45 | enum Actions { Increment } 46 | 47 | // The reducer, which takes the previous count and increments it in response 48 | // to an Increment action. 49 | int counterReducer(int state, dynamic action) { 50 | return action == Actions.Increment ? state + 1 : state; 51 | } 52 | 53 | void main() { 54 | // Create your store as a final variable in the main function or inside a 55 | // State object. This works better with Hot Reload than creating it directly 56 | // in the `build` function. 57 | final store = Store(counterReducer, initialState: 0); 58 | 59 | runApp(FlutterReduxApp( 60 | title: 'Flutter Redux Demo', 61 | store: store, 62 | )); 63 | } 64 | 65 | class FlutterReduxApp extends StatelessWidget { 66 | final Store store; 67 | final String title; 68 | 69 | FlutterReduxApp({Key key, this.store, this.title}) : super(key: key); 70 | 71 | @override 72 | Widget build(BuildContext context) { 73 | // The StoreProvider should wrap your MaterialApp or WidgetsApp. This will 74 | // ensure all routes have access to the store. 75 | return StoreProvider( 76 | // Pass the store to the StoreProvider. Any ancestor `StoreConnector` 77 | // Widgets will find and use this value as the `Store`. 78 | store: store, 79 | child: MaterialApp( 80 | theme: ThemeData.dark(), 81 | title: title, 82 | home: Scaffold( 83 | appBar: AppBar(title: Text(title)), 84 | body: Center( 85 | child: Column( 86 | mainAxisAlignment: MainAxisAlignment.center, 87 | children: [ 88 | // Connect the Store to a Text Widget that renders the current 89 | // count. 90 | // 91 | // We'll wrap the Text Widget in a `StoreConnector` Widget. The 92 | // `StoreConnector` will find the `Store` from the nearest 93 | // `StoreProvider` ancestor, convert it into a String of the 94 | // latest count, and pass that String to the `builder` function 95 | // as the `count`. 96 | // 97 | // Every time the button is tapped, an action is dispatched and 98 | // run through the reducer. After the reducer updates the state, 99 | // the Widget will be automatically rebuilt with the latest 100 | // count. No need to manually manage subscriptions or Streams! 101 | StoreConnector( 102 | converter: (store) => store.state.toString(), 103 | builder: (context, count) { 104 | return Text( 105 | 'The button has been pushed this many times: $count', 106 | style: Theme.of(context).textTheme.display1, 107 | ); 108 | }, 109 | ) 110 | ], 111 | ), 112 | ), 113 | // Connect the Store to a FloatingActionButton. In this case, we'll 114 | // use the Store to build a callback that will dispatch an Increment 115 | // Action. 116 | // 117 | // Then, we'll pass this callback to the button's `onPressed` handler. 118 | floatingActionButton: StoreConnector( 119 | converter: (store) { 120 | // Return a `VoidCallback`, which is a fancy name for a function 121 | // with no parameters and no return value. 122 | // It only dispatches an Increment action. 123 | return () => store.dispatch(Actions.Increment); 124 | }, 125 | builder: (context, callback) { 126 | return FloatingActionButton( 127 | // Attach the `callback` to the `onPressed` attribute 128 | onPressed: callback, 129 | tooltip: 'Increment', 130 | child: Icon(Icons.add), 131 | ); 132 | }, 133 | ), 134 | ), 135 | ), 136 | ); 137 | } 138 | } 139 | ``` 140 | 141 | ## Purpose 142 | 143 | One question that [reasonable people might 144 | ask](https://www.reddit.com/r/FlutterDev/comments/6vscdy/a_set_of_utilities_that_allow_you_to_easily/dm3ll7d/): 145 | Why do you need all of this if `StatefulWidget` exists? 146 | 147 | My advice is the same as the original Redux.JS author: If you've got a simple 148 | app, use the most straightforward thing possible. In Flutter, `StatefulWidget` is perfect 149 | for a simple counter app. 150 | 151 | However, say you have the more complex app, such as an E-commerce app with a 152 | Shopping Cart. The Shopping Cart should appear on multiple screens in your app 153 | and should be updated by many different types of Widgets on those different 154 | screens (An "Add Item to Cart" Widget on all your Product Screens, "Remove Item 155 | from Cart" Widget on the Shopping Cart Screen, "Change quantity" Widgets, etc.). 156 | 157 | Additionally, you want to test this logic, as it's the core business 158 | logic to your app! 159 | 160 | Now, in this case, you could create a Testable `ShoppingCart` class as a 161 | Singleton or Create a Root `StatefulWidget` that passes the `ShoppingCart `*Down 162 | Down Down* through your widget hierarchy to the "add to cart" or "remove from 163 | cart" Widgets. 164 | 165 | Singletons can be problematic for testing, and Flutter doesn't have a great 166 | Dependency Injection library (such as Dagger2) just yet, so I'd prefer to avoid 167 | those. 168 | 169 | Yet passing the ShoppingCart all over the place can get messy. It also means 170 | it's way harder to move that "Add to Item" button to a new location b/c you'd 171 | need up update the Widgets throughout your app that passes the state down. 172 | 173 | Furthermore, you'd need a way to Observe when the `ShoppingCart` Changes so you 174 | could rebuild your Widgets when it does (from an "Add" button to an "Added" 175 | button, as an example). 176 | 177 | One way to handle it would be to simply `setState` every time the `ShoppingCart` 178 | changes in your Root Widget, but then your whole app below the RootWidget would 179 | be required to rebuild as well! Flutter is fast, but we should be thoughtful about 180 | what we ask Flutter to rebuild! 181 | 182 | Therefore, `redux` & `redux_flutter` was born for more complex stories like this 183 | one. It gives you a set of tools that allow your Widgets to `dispatch` actions 184 | in a naive way, then writes the business logic in another place that will take 185 | those actions and update the `ShoppingCart` in a safe, testable way. 186 | 187 | Even more, once the `ShoppingCart` has been updated in the `Store`, the `Store` 188 | will emit an `onChange` event. This lets you listen to `Store` updates and 189 | rebuild your UI in the right places when it changes! Now, you can separate your 190 | business logic from your UI logic in a testable, observable way, without having 191 | to Wire up a bunch of stuff yourself! 192 | 193 | Similar patterns in Android are the MVP Pattern or using Rx Observables to 194 | manage a View's State. 195 | 196 | `flutter_redux` handles passing your `Store` down to all of your 197 | descendant `StoreConnector` Widgets. If your State emits a change event, only 198 | the `StoreConnector` Widgets and their descendants will be automatically rebuilt 199 | with the latest State of the `Store`! 200 | 201 | This allows you to focus on what your app should look like and how it should 202 | work without thinking about all the glue code to hook everything together! 203 | 204 | ### Contributors 205 | 206 | * [Brian Egan](https://github.com/brianegan) 207 | * [Chris Bird](https://github.com/chrisabird) 208 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:pedantic/analysis_options.yaml 2 | 3 | analyzer: 4 | strong-mode: 5 | implicit-casts: false 6 | implicit-dynamic: false 7 | 8 | linter: 9 | rules: 10 | - public_member_api_docs 11 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | ## Examples 2 | 3 | * [Simple example](https://github.com/brianegan/flutter_redux/tree/master/example/counter) - a port of the standard "Counter Button" example from Flutter 4 | * [Github Search](https://github.com/brianegan/flutter_redux/tree/master/example/github_search) - an example of how to search as a user types, demonstrating both the Middleware and Epic approaches. -------------------------------------------------------------------------------- /example/counter/.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 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Web related 35 | lib/generated_plugin_registrant.dart 36 | 37 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | 43 | # Android Studio will place build artifacts here 44 | /android/app/debug 45 | /android/app/profile 46 | /android/app/release 47 | -------------------------------------------------------------------------------- /example/counter/.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: 8962f6dc68ec8e2206ac2fa874da4a453856c7d3 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /example/counter/README.md: -------------------------------------------------------------------------------- 1 | # example 2 | 3 | A new Flutter project. 4 | 5 | ## Getting Started 6 | 7 | For help getting started with Flutter, view our online 8 | [documentation](http://flutter.io/). 9 | -------------------------------------------------------------------------------- /example/counter/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:pedantic/analysis_options.yaml 2 | -------------------------------------------------------------------------------- /example/counter/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/counter/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.counter" 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/counter/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/counter/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 13 | 17 | 21 | 26 | 30 | 31 | 32 | 33 | 34 | 35 | 37 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /example/counter/android/app/src/main/kotlin/com/example/counter/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.counter 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /example/counter/android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/counter/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/counter/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/counter/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/counter/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/counter/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/counter/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/counter/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/counter/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/counter/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/counter/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/counter/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/counter/android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /example/counter/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /example/counter/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/counter/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/counter/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /example/counter/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/counter/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/counter/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/counter/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/counter/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /example/counter/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /example/counter/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.counter; 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.counter; 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.counter; 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/counter/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/counter/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/counter/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/counter/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/counter/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/counter/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/counter/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/counter/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/counter/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/counter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/counter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /example/counter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/counter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /example/counter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/counter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /example/counter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/counter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /example/counter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/counter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /example/counter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/counter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /example/counter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/counter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /example/counter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/counter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /example/counter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/counter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /example/counter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/counter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /example/counter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/counter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /example/counter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/counter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /example/counter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/counter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /example/counter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/counter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /example/counter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/counter/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /example/counter/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/counter/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/counter/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /example/counter/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/counter/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /example/counter/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/counter/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /example/counter/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/counter/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/counter/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/counter/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 | counter 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/counter/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /example/counter/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_redux/flutter_redux.dart'; 3 | import 'package:redux/redux.dart'; 4 | 5 | // One simple action: Increment 6 | enum Actions { Increment } 7 | 8 | // The reducer, which takes the previous count and increments it in response 9 | // to an Increment action. 10 | int counterReducer(int state, dynamic action) { 11 | if (action == Actions.Increment) { 12 | return state + 1; 13 | } 14 | 15 | return state; 16 | } 17 | 18 | void main() { 19 | // Create your store as a final variable in the main function or inside a 20 | // State object. This works better with Hot Reload than creating it directly 21 | // in the `build` function. 22 | final store = Store(counterReducer, initialState: 0); 23 | 24 | runApp(FlutterReduxApp( 25 | title: 'Flutter Redux Demo', 26 | store: store, 27 | )); 28 | } 29 | 30 | class FlutterReduxApp extends StatelessWidget { 31 | final Store store; 32 | final String title; 33 | 34 | FlutterReduxApp({ 35 | Key? key, 36 | required this.store, 37 | required this.title, 38 | }) : super(key: key); 39 | 40 | @override 41 | Widget build(BuildContext context) { 42 | // The StoreProvider should wrap your MaterialApp or WidgetsApp. This will 43 | // ensure all routes have access to the store. 44 | return StoreProvider( 45 | // Pass the store to the StoreProvider. Any ancestor `StoreConnector` 46 | // Widgets will find and use this value as the `Store`. 47 | store: store, 48 | child: MaterialApp( 49 | theme: ThemeData.dark(), 50 | title: title, 51 | home: Scaffold( 52 | appBar: AppBar( 53 | title: Text(title), 54 | ), 55 | body: Center( 56 | child: Column( 57 | mainAxisAlignment: MainAxisAlignment.center, 58 | children: [ 59 | // Connect the Store to a Text Widget that renders the current 60 | // count. 61 | // 62 | // We'll wrap the Text Widget in a `StoreConnector` Widget. The 63 | // `StoreConnector` will find the `Store` from the nearest 64 | // `StoreProvider` ancestor, convert it into a String of the 65 | // latest count, and pass that String to the `builder` function 66 | // as the `count`. 67 | // 68 | // Every time the button is tapped, an action is dispatched and 69 | // run through the reducer. After the reducer updates the state, 70 | // the Widget will be automatically rebuilt with the latest 71 | // count. No need to manually manage subscriptions or Streams! 72 | StoreConnector( 73 | converter: (store) => store.state.toString(), 74 | builder: (context, count) { 75 | return Text( 76 | 'The button has been pushed this many times: $count', 77 | style: Theme.of(context).textTheme.headline4, 78 | ); 79 | }, 80 | ) 81 | ], 82 | ), 83 | ), 84 | // Connect the Store to a FloatingActionButton. In this case, we'll 85 | // use the Store to build a callback that will dispatch an Increment 86 | // Action. 87 | // 88 | // Then, we'll pass this callback to the button's `onPressed` handler. 89 | floatingActionButton: StoreConnector( 90 | converter: (store) { 91 | // Return a `VoidCallback`, which is a fancy name for a function 92 | // with no parameters and no return value. 93 | // It only dispatches an Increment action. 94 | return () => store.dispatch(Actions.Increment); 95 | }, 96 | builder: (context, callback) { 97 | return FloatingActionButton( 98 | // Attach the `callback` to the `onPressed` attribute 99 | onPressed: callback, 100 | tooltip: 'Increment', 101 | child: Icon(Icons.add), 102 | ); 103 | }, 104 | ), 105 | ), 106 | ), 107 | ); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /example/counter/linux/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral 2 | -------------------------------------------------------------------------------- /example/counter/linux/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | project(runner LANGUAGES CXX) 3 | 4 | set(BINARY_NAME "counter") 5 | set(APPLICATION_ID "com.example.counter") 6 | 7 | cmake_policy(SET CMP0063 NEW) 8 | 9 | set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") 10 | 11 | # Configure build options. 12 | if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) 13 | set(CMAKE_BUILD_TYPE "Debug" CACHE 14 | STRING "Flutter build mode" FORCE) 15 | set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS 16 | "Debug" "Profile" "Release") 17 | endif() 18 | 19 | # Compilation settings that should be applied to most targets. 20 | function(APPLY_STANDARD_SETTINGS TARGET) 21 | target_compile_features(${TARGET} PUBLIC cxx_std_14) 22 | target_compile_options(${TARGET} PRIVATE -Wall -Werror) 23 | target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") 24 | target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") 25 | endfunction() 26 | 27 | set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") 28 | 29 | # Flutter library and tool build rules. 30 | add_subdirectory(${FLUTTER_MANAGED_DIR}) 31 | 32 | # System-level dependencies. 33 | find_package(PkgConfig REQUIRED) 34 | pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) 35 | 36 | add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") 37 | 38 | # Application build 39 | add_executable(${BINARY_NAME} 40 | "main.cc" 41 | "my_application.cc" 42 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" 43 | ) 44 | apply_standard_settings(${BINARY_NAME}) 45 | target_link_libraries(${BINARY_NAME} PRIVATE flutter) 46 | target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) 47 | add_dependencies(${BINARY_NAME} flutter_assemble) 48 | # Only the install-generated bundle's copy of the executable will launch 49 | # correctly, since the resources must in the right relative locations. To avoid 50 | # people trying to run the unbundled copy, put it in a subdirectory instead of 51 | # the default top-level location. 52 | set_target_properties(${BINARY_NAME} 53 | PROPERTIES 54 | RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" 55 | ) 56 | 57 | # Generated plugin build rules, which manage building the plugins and adding 58 | # them to the application. 59 | include(flutter/generated_plugins.cmake) 60 | 61 | 62 | # === Installation === 63 | # By default, "installing" just makes a relocatable bundle in the build 64 | # directory. 65 | set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") 66 | if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) 67 | set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) 68 | endif() 69 | 70 | # Start with a clean build bundle directory every time. 71 | install(CODE " 72 | file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") 73 | " COMPONENT Runtime) 74 | 75 | set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") 76 | set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") 77 | 78 | install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" 79 | COMPONENT Runtime) 80 | 81 | install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" 82 | COMPONENT Runtime) 83 | 84 | install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 85 | COMPONENT Runtime) 86 | 87 | if(PLUGIN_BUNDLED_LIBRARIES) 88 | install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" 89 | DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 90 | COMPONENT Runtime) 91 | endif() 92 | 93 | # Fully re-copy the assets directory on each build to avoid having stale files 94 | # from a previous install. 95 | set(FLUTTER_ASSET_DIR_NAME "flutter_assets") 96 | install(CODE " 97 | file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") 98 | " COMPONENT Runtime) 99 | install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" 100 | DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) 101 | 102 | # Install the AOT library on non-Debug builds only. 103 | if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") 104 | install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 105 | COMPONENT Runtime) 106 | endif() 107 | -------------------------------------------------------------------------------- /example/counter/linux/flutter/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 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 | 11 | # Serves the same purpose as list(TRANSFORM ... PREPEND ...), 12 | # which isn't available in 3.10. 13 | function(list_prepend LIST_NAME PREFIX) 14 | set(NEW_LIST "") 15 | foreach(element ${${LIST_NAME}}) 16 | list(APPEND NEW_LIST "${PREFIX}${element}") 17 | endforeach(element) 18 | set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) 19 | endfunction() 20 | 21 | # === Flutter Library === 22 | # System-level dependencies. 23 | find_package(PkgConfig REQUIRED) 24 | pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) 25 | pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) 26 | pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) 27 | pkg_check_modules(BLKID REQUIRED IMPORTED_TARGET blkid) 28 | pkg_check_modules(LZMA REQUIRED IMPORTED_TARGET liblzma) 29 | 30 | set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") 31 | 32 | # Published to parent scope for install step. 33 | set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) 34 | set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) 35 | set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) 36 | set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) 37 | 38 | list(APPEND FLUTTER_LIBRARY_HEADERS 39 | "fl_basic_message_channel.h" 40 | "fl_binary_codec.h" 41 | "fl_binary_messenger.h" 42 | "fl_dart_project.h" 43 | "fl_engine.h" 44 | "fl_json_message_codec.h" 45 | "fl_json_method_codec.h" 46 | "fl_message_codec.h" 47 | "fl_method_call.h" 48 | "fl_method_channel.h" 49 | "fl_method_codec.h" 50 | "fl_method_response.h" 51 | "fl_plugin_registrar.h" 52 | "fl_plugin_registry.h" 53 | "fl_standard_message_codec.h" 54 | "fl_standard_method_codec.h" 55 | "fl_string_codec.h" 56 | "fl_value.h" 57 | "fl_view.h" 58 | "flutter_linux.h" 59 | ) 60 | list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") 61 | add_library(flutter INTERFACE) 62 | target_include_directories(flutter INTERFACE 63 | "${EPHEMERAL_DIR}" 64 | ) 65 | target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") 66 | target_link_libraries(flutter INTERFACE 67 | PkgConfig::GTK 68 | PkgConfig::GLIB 69 | PkgConfig::GIO 70 | PkgConfig::BLKID 71 | PkgConfig::LZMA 72 | ) 73 | add_dependencies(flutter flutter_assemble) 74 | 75 | # === Flutter tool backend === 76 | # _phony_ is a non-existent file to force this command to run every time, 77 | # since currently there's no way to get a full input/output list from the 78 | # flutter tool. 79 | add_custom_command( 80 | OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} 81 | ${CMAKE_CURRENT_BINARY_DIR}/_phony_ 82 | COMMAND ${CMAKE_COMMAND} -E env 83 | ${FLUTTER_TOOL_ENVIRONMENT} 84 | "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" 85 | linux-x64 ${CMAKE_BUILD_TYPE} 86 | VERBATIM 87 | ) 88 | add_custom_target(flutter_assemble DEPENDS 89 | "${FLUTTER_LIBRARY}" 90 | ${FLUTTER_LIBRARY_HEADERS} 91 | ) 92 | -------------------------------------------------------------------------------- /example/counter/linux/flutter/generated_plugin_registrant.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | #include "generated_plugin_registrant.h" 6 | 7 | 8 | void fl_register_plugins(FlPluginRegistry* registry) { 9 | } 10 | -------------------------------------------------------------------------------- /example/counter/linux/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 6 | #define GENERATED_PLUGIN_REGISTRANT_ 7 | 8 | #include 9 | 10 | // Registers Flutter plugins. 11 | void fl_register_plugins(FlPluginRegistry* registry); 12 | 13 | #endif // GENERATED_PLUGIN_REGISTRANT_ 14 | -------------------------------------------------------------------------------- /example/counter/linux/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | ) 7 | 8 | set(PLUGIN_BUNDLED_LIBRARIES) 9 | 10 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 11 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) 12 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 13 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 14 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 15 | endforeach(plugin) 16 | -------------------------------------------------------------------------------- /example/counter/linux/main.cc: -------------------------------------------------------------------------------- 1 | #include "my_application.h" 2 | 3 | int main(int argc, char** argv) { 4 | g_autoptr(MyApplication) app = my_application_new(); 5 | return g_application_run(G_APPLICATION(app), argc, argv); 6 | } 7 | -------------------------------------------------------------------------------- /example/counter/linux/my_application.cc: -------------------------------------------------------------------------------- 1 | #include "my_application.h" 2 | 3 | #include 4 | #ifdef GDK_WINDOWING_X11 5 | #include 6 | #endif 7 | 8 | #include "flutter/generated_plugin_registrant.h" 9 | 10 | struct _MyApplication { 11 | GtkApplication parent_instance; 12 | char** dart_entrypoint_arguments; 13 | }; 14 | 15 | G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) 16 | 17 | // Implements GApplication::activate. 18 | static void my_application_activate(GApplication* application) { 19 | MyApplication* self = MY_APPLICATION(application); 20 | GtkWindow* window = 21 | GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); 22 | 23 | // Use a header bar when running in GNOME as this is the common style used 24 | // by applications and is the setup most users will be using (e.g. Ubuntu 25 | // desktop). 26 | // If running on X and not using GNOME then just use a traditional title bar 27 | // in case the window manager does more exotic layout, e.g. tiling. 28 | // If running on Wayland assume the header bar will work (may need changing 29 | // if future cases occur). 30 | gboolean use_header_bar = TRUE; 31 | #ifdef GDK_WINDOWING_X11 32 | GdkScreen *screen = gtk_window_get_screen(window); 33 | if (GDK_IS_X11_SCREEN(screen)) { 34 | const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); 35 | if (g_strcmp0(wm_name, "GNOME Shell") != 0) { 36 | use_header_bar = FALSE; 37 | } 38 | } 39 | #endif 40 | if (use_header_bar) { 41 | GtkHeaderBar *header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); 42 | gtk_widget_show(GTK_WIDGET(header_bar)); 43 | gtk_header_bar_set_title(header_bar, "counter"); 44 | gtk_header_bar_set_show_close_button(header_bar, TRUE); 45 | gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); 46 | } 47 | else { 48 | gtk_window_set_title(window, "counter"); 49 | } 50 | 51 | gtk_window_set_default_size(window, 1280, 720); 52 | gtk_widget_show(GTK_WIDGET(window)); 53 | 54 | g_autoptr(FlDartProject) project = fl_dart_project_new(); 55 | fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); 56 | 57 | FlView* view = fl_view_new(project); 58 | gtk_widget_show(GTK_WIDGET(view)); 59 | gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); 60 | 61 | fl_register_plugins(FL_PLUGIN_REGISTRY(view)); 62 | 63 | gtk_widget_grab_focus(GTK_WIDGET(view)); 64 | } 65 | 66 | // Implements GApplication::local_command_line. 67 | static gboolean my_application_local_command_line(GApplication* application, gchar ***arguments, int *exit_status) { 68 | MyApplication* self = MY_APPLICATION(application); 69 | // Strip out the first argument as it is the binary name. 70 | self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); 71 | 72 | g_autoptr(GError) error = nullptr; 73 | if (!g_application_register(application, nullptr, &error)) { 74 | g_warning("Failed to register: %s", error->message); 75 | *exit_status = 1; 76 | return TRUE; 77 | } 78 | 79 | g_application_activate(application); 80 | *exit_status = 0; 81 | 82 | return TRUE; 83 | } 84 | 85 | // Implements GObject::dispose. 86 | static void my_application_dispose(GObject *object) { 87 | MyApplication* self = MY_APPLICATION(object); 88 | g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); 89 | G_OBJECT_CLASS(my_application_parent_class)->dispose(object); 90 | } 91 | 92 | static void my_application_class_init(MyApplicationClass* klass) { 93 | G_APPLICATION_CLASS(klass)->activate = my_application_activate; 94 | G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; 95 | G_OBJECT_CLASS(klass)->dispose = my_application_dispose; 96 | } 97 | 98 | static void my_application_init(MyApplication* self) {} 99 | 100 | MyApplication* my_application_new() { 101 | return MY_APPLICATION(g_object_new(my_application_get_type(), 102 | "application-id", APPLICATION_ID, 103 | nullptr)); 104 | } 105 | -------------------------------------------------------------------------------- /example/counter/linux/my_application.h: -------------------------------------------------------------------------------- 1 | #ifndef FLUTTER_MY_APPLICATION_H_ 2 | #define FLUTTER_MY_APPLICATION_H_ 3 | 4 | #include 5 | 6 | G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, 7 | GtkApplication) 8 | 9 | /** 10 | * my_application_new: 11 | * 12 | * Creates a new Flutter-based application. 13 | * 14 | * Returns: a new #MyApplication. 15 | */ 16 | MyApplication* my_application_new(); 17 | 18 | #endif // FLUTTER_MY_APPLICATION_H_ 19 | -------------------------------------------------------------------------------- /example/counter/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: example 2 | description: A new Flutter project. 3 | 4 | environment: 5 | sdk: ">=2.12.0 <3.0.0" 6 | 7 | dependencies: 8 | flutter: 9 | sdk: flutter 10 | 11 | dev_dependencies: 12 | flutter_redux: 13 | path: ../../ 14 | flutter_test: 15 | sdk: flutter 16 | pedantic: 1.10.0 17 | 18 | # For information on the generic Dart part of this file, see the 19 | # following page: https://www.dartlang.org/tools/pub/pubspec 20 | 21 | # The following section is specific to Flutter. 22 | flutter: 23 | 24 | # The following line ensures that the Material Icons font is 25 | # included with your application, so that you can use the icons in 26 | # the Icons class. 27 | uses-material-design: true 28 | 29 | # To add assets to your application, add an assets section, like this: 30 | # assets: 31 | # - images/a_dot_burr.jpeg 32 | # - images/a_dot_ham.jpeg 33 | 34 | # An image asset can refer to one or more resolution-specific "variants", see 35 | # https://flutter.io/assets-and-images/. 36 | 37 | # To add assets from package dependencies, first ensure the asset 38 | # is in the lib/ directory of the dependency. Then, 39 | # refer to the asset with a path prefixed with 40 | # `packages/PACKAGE_NAME/`. The `lib/` is implied, do not 41 | # include `lib/` in the asset path. 42 | # 43 | # Here is an example: 44 | # 45 | # assets: 46 | # - packages/PACKAGE_NAME/path/to/asset 47 | 48 | # To add custom fonts to your application, add a fonts section here, 49 | # in this "flutter" section. Each entry in this list should have a 50 | # "family" key with the font family name, and a "fonts" key with a 51 | # list giving the asset and other descriptors for the font. For 52 | # example: 53 | # fonts: 54 | # - family: Schyler 55 | # fonts: 56 | # - asset: fonts/Schyler-Regular.ttf 57 | # - asset: fonts/Schyler-Italic.ttf 58 | # style: italic 59 | # - family: Trajan Pro 60 | # fonts: 61 | # - asset: fonts/TrajanPro.ttf 62 | # - asset: fonts/TrajanPro_Bold.ttf 63 | # weight: 700 64 | -------------------------------------------------------------------------------- /example/counter/web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/counter/web/favicon.png -------------------------------------------------------------------------------- /example/counter/web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/counter/web/icons/Icon-192.png -------------------------------------------------------------------------------- /example/counter/web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/counter/web/icons/Icon-512.png -------------------------------------------------------------------------------- /example/counter/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | counter 30 | 31 | 32 | 33 | 36 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /example/counter/web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "counter", 3 | "short_name": "counter", 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/github_search/.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 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Web related 35 | lib/generated_plugin_registrant.dart 36 | 37 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | 43 | # Android Studio will place build artifacts here 44 | /android/app/debug 45 | /android/app/profile 46 | /android/app/release 47 | -------------------------------------------------------------------------------- /example/github_search/.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: 8962f6dc68ec8e2206ac2fa874da4a453856c7d3 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /example/github_search/README.md: -------------------------------------------------------------------------------- 1 | ## Flutter Github Search Example 2 | 3 | This example makes use of the bloc pattern [presented by Paolo Soares at DartConf](https://www.youtube.com/watch?v=PLHln7wHgPE). 4 | 5 | ### Run the example 6 | 7 | This example requires Dart 2 be enabled. To run the example: 8 | 9 | `flutter run --preview-dart-2` 10 | -------------------------------------------------------------------------------- /example/github_search/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:pedantic/analysis_options.yaml 2 | 3 | analyzer: 4 | strong-mode: 5 | implicit-casts: false 6 | implicit-dynamic: false 7 | -------------------------------------------------------------------------------- /example/github_search/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/github_search/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.github_search" 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/github_search/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/github_search/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 13 | 17 | 21 | 26 | 30 | 31 | 32 | 33 | 34 | 35 | 37 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /example/github_search/android/app/src/main/kotlin/com/example/github_search/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.github_search 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /example/github_search/android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/github_search/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/github_search/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/github_search/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/github_search/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/github_search/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/github_search/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/github_search/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/github_search/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/github_search/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/github_search/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/github_search/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/github_search/android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /example/github_search/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /example/github_search/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/github_search/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/github_search/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /example/github_search/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/github_search/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/github_search/fonts/hind/DESCRIPTION.en_us.html: -------------------------------------------------------------------------------- 1 |

Hind is an Open Source typeface supporting the Devanagari and Latin scripts. Developed explicitly for use in User Interface design, the Hind font family includes five styles. Hind’s letterforms have a humanist-style construction, which is paired with seemingly monolinear strokes. Most of these strokes have flat endings: they either terminate with a horizontal or a vertical shear, rather than on a diagonal. This helps create clear-cut counter forms between the characters. In addition to this, Hind’s letterforms feature open apertures. The entire typeface family feels very legible when used to set text.

2 | 3 |

The Devanagari and Latin script components are scaled in relation to each other so that the Devanagari headline falls just below the Latin capital-height. In other words, the Devanagari base characters are 94% as tall as the Latin uppercase. Text set in the Devanagari script sits nicely alongside the Latin lowercase, too. Hind’s Devanagari vowel marks take forms that tends toward the traditional end of the design spectrum, while the knotted terminals, etc. inside of the base characters feature a treatment that appears more contemporary.

4 | 5 |

Each font in the Hind family has 1146 glyphs, which include hundreds of unique Devanagari conjuncts. These ensure full support for the major languages written with the Devanagari script. The Latin component’s character set is a basic western one, which enables typesetting in English and the other Western European languages. Hind is a solid choice for UI design, and a wise selection for electronic display embedding.

6 | 7 |

Manushi Parikh designed Hind for the Indian Type Foundry, who first published the fonts in 2014.

-------------------------------------------------------------------------------- /example/github_search/fonts/hind/Hind-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/github_search/fonts/hind/Hind-Bold.ttf -------------------------------------------------------------------------------- /example/github_search/fonts/hind/Hind-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/github_search/fonts/hind/Hind-Light.ttf -------------------------------------------------------------------------------- /example/github_search/fonts/hind/Hind-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/github_search/fonts/hind/Hind-Medium.ttf -------------------------------------------------------------------------------- /example/github_search/fonts/hind/Hind-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/github_search/fonts/hind/Hind-Regular.ttf -------------------------------------------------------------------------------- /example/github_search/fonts/hind/Hind-Semibold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/github_search/fonts/hind/Hind-Semibold.ttf -------------------------------------------------------------------------------- /example/github_search/fonts/hind/METADATA.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Hind", 3 | "designer": "Indian Type Foundry", 4 | "license": "OFL", 5 | "visibility": "External", 6 | "category": "Sans Serif", 7 | "size": 79589, 8 | "fonts": [ 9 | { 10 | "name": "Hind", 11 | "style": "normal", 12 | "weight": 700, 13 | "filename": "Hind-Bold.ttf", 14 | "postScriptName": "Hind-Bold", 15 | "fullName": "Hind Bold", 16 | "copyright": "Copyright (c) 2014 Indian Type Foundry (info@indiantypefoundry.com)" 17 | }, 18 | { 19 | "name": "Hind", 20 | "style": "normal", 21 | "weight": 300, 22 | "filename": "Hind-Light.ttf", 23 | "postScriptName": "Hind-Light", 24 | "fullName": "Hind Light", 25 | "copyright": "Copyright (c) 2014 Indian Type Foundry (info@indiantypefoundry.com)" 26 | }, 27 | { 28 | "name": "Hind", 29 | "style": "normal", 30 | "weight": 500, 31 | "filename": "Hind-Medium.ttf", 32 | "postScriptName": "Hind-Medium", 33 | "fullName": "Hind Medium", 34 | "copyright": "Copyright (c) 2014 Indian Type Foundry (info@indiantypefoundry.com)" 35 | }, 36 | { 37 | "name": "Hind", 38 | "style": "normal", 39 | "weight": 400, 40 | "filename": "Hind-Regular.ttf", 41 | "postScriptName": "Hind-Regular", 42 | "fullName": "Hind Regular", 43 | "copyright": "Copyright (c) 2014 Indian Type Foundry (info@indiantypefoundry.com)" 44 | }, 45 | { 46 | "name": "Hind", 47 | "style": "normal", 48 | "weight": 600, 49 | "filename": "Hind-Semibold.ttf", 50 | "postScriptName": "Hind-Semibold", 51 | "fullName": "Hind Semibold", 52 | "copyright": "Copyright (c) 2014 Indian Type Foundry (info@indiantypefoundry.com)" 53 | } 54 | ], 55 | "subsets": [ 56 | "latin", 57 | "latin-ext", 58 | "devanagari", 59 | "menu" 60 | ], 61 | "dateAdded": "2014-06-25" 62 | } 63 | -------------------------------------------------------------------------------- /example/github_search/fonts/hind/OFL.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, Indian Type Foundry (info@indiantypefoundry.com). 2 | 3 | This Font Software is licensed under the SIL Open Font License, Version 1.1. 4 | This license is copied below, and is also available with a FAQ at: 5 | http://scripts.sil.org/OFL 6 | 7 | 8 | ----------------------------------------------------------- 9 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 10 | ----------------------------------------------------------- 11 | 12 | PREAMBLE 13 | The goals of the Open Font License (OFL) are to stimulate worldwide 14 | development of collaborative font projects, to support the font creation 15 | efforts of academic and linguistic communities, and to provide a free and 16 | open framework in which fonts may be shared and improved in partnership 17 | with others. 18 | 19 | The OFL allows the licensed fonts to be used, studied, modified and 20 | redistributed freely as long as they are not sold by themselves. The 21 | fonts, including any derivative works, can be bundled, embedded, 22 | redistributed and/or sold with any software provided that any reserved 23 | names are not used by derivative works. The fonts and derivatives, 24 | however, cannot be released under any other type of license. The 25 | requirement for fonts to remain under this license does not apply 26 | to any document created using the fonts or their derivatives. 27 | 28 | DEFINITIONS 29 | "Font Software" refers to the set of files released by the Copyright 30 | Holder(s) under this license and clearly marked as such. This may 31 | include source files, build scripts and documentation. 32 | 33 | "Reserved Font Name" refers to any names specified as such after the 34 | copyright statement(s). 35 | 36 | "Original Version" refers to the collection of Font Software components as 37 | distributed by the Copyright Holder(s). 38 | 39 | "Modified Version" refers to any derivative made by adding to, deleting, 40 | or substituting -- in part or in whole -- any of the components of the 41 | Original Version, by changing formats or by porting the Font Software to a 42 | new environment. 43 | 44 | "Author" refers to any designer, engineer, programmer, technical 45 | writer or other person who contributed to the Font Software. 46 | 47 | PERMISSION & CONDITIONS 48 | Permission is hereby granted, free of charge, to any person obtaining 49 | a copy of the Font Software, to use, study, copy, merge, embed, modify, 50 | redistribute, and sell modified and unmodified copies of the Font 51 | Software, subject to the following conditions: 52 | 53 | 1) Neither the Font Software nor any of its individual components, 54 | in Original or Modified Versions, may be sold by itself. 55 | 56 | 2) Original or Modified Versions of the Font Software may be bundled, 57 | redistributed and/or sold with any software, provided that each copy 58 | contains the above copyright notice and this license. These can be 59 | included either as stand-alone text files, human-readable headers or 60 | in the appropriate machine-readable metadata fields within text or 61 | binary files as long as those fields can be easily viewed by the user. 62 | 63 | 3) No Modified Version of the Font Software may use the Reserved Font 64 | Name(s) unless explicit written permission is granted by the corresponding 65 | Copyright Holder. This restriction only applies to the primary font name as 66 | presented to the users. 67 | 68 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font 69 | Software shall not be used to promote, endorse or advertise any 70 | Modified Version, except to acknowledge the contribution(s) of the 71 | Copyright Holder(s) and the Author(s) or with their explicit written 72 | permission. 73 | 74 | 5) The Font Software, modified or unmodified, in part or in whole, 75 | must be distributed entirely under this license, and must not be 76 | distributed under any other license. The requirement for fonts to 77 | remain under this license does not apply to any document created 78 | using the Font Software. 79 | 80 | TERMINATION 81 | This license becomes null and void if any of the above conditions are 82 | not met. 83 | 84 | DISCLAIMER 85 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 86 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 87 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 88 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 89 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 90 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 91 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 92 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM 93 | OTHER DEALINGS IN THE FONT SOFTWARE. 94 | -------------------------------------------------------------------------------- /example/github_search/fonts/montserrat/DESCRIPTION.en_us.html: -------------------------------------------------------------------------------- 1 |

The old posters and signs in the traditional neighborhood of Buenos Aires 2 | called Montserrat inspired me to design a typeface that rescues the beauty of 3 | urban typography from the first half of the twentieth century. The goal is to 4 | rescue what is in Montserrat and set it free, under a free, libre and open 5 | source license, the SIL Open Font License.

6 | 7 |

As urban development changes this place, it will never return to its 8 | original form and loses forever the designs that are so special and unique. To 9 | draw the letters, I rely on examples of lettering in the urban space. Each 10 | selected example produces its own variants in length, width and height 11 | proportions, each adding to the Montserrat family. The old typographies and 12 | canopies are irretrievable when they are replaced.

13 | 14 |

There are other revivals, but those do not stay close to the originals. The 15 | letters that inspired this project have work, dedication, care, color, 16 | contrast, light and life, day and night! These are the types that make the 17 | city look so beautiful.

18 | 19 |

This is the Regular family, and it has two sister families so far, 20 | Alternates and 21 | Subrayada 22 | families. Many of the letterforms are special in the Alternates family, 23 | while .

24 | 25 |

Updated in September 2012.

26 | 27 |

Updated in June 2014, with Thin, Light and Black weights.

28 | -------------------------------------------------------------------------------- /example/github_search/fonts/montserrat/METADATA.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Montserrat", 3 | "designer": "Julieta Ulanovsky", 4 | "license": "OFL", 5 | "visibility": "External", 6 | "category": "Sans Serif", 7 | "size": 14615, 8 | "fonts": [ 9 | { 10 | "name": "Montserrat", 11 | "style": "normal", 12 | "weight": 900, 13 | "filename": "Montserrat-Black.ttf", 14 | "postScriptName": "Montserrat-Black", 15 | "fullName": "Montserrat Black", 16 | "copyright": "Copyright \u00a9 2014 by Julieta Ulanovsky. All rights reserved." 17 | }, 18 | { 19 | "name": "Montserrat", 20 | "style": "normal", 21 | "weight": 700, 22 | "filename": "Montserrat-Bold.ttf", 23 | "postScriptName": "Montserrat-Bold", 24 | "fullName": "Montserrat Bold", 25 | "copyright": "Copyright \u00a9 2014 by Julieta Ulanovsky. All rights reserved." 26 | }, 27 | { 28 | "name": "Montserrat", 29 | "style": "normal", 30 | "weight": 300, 31 | "filename": "Montserrat-Light.ttf", 32 | "postScriptName": "Montserrat-Light", 33 | "fullName": "Montserrat Light", 34 | "copyright": "Copyright \u00a9 2014 by Julieta Ulanovsky. All rights reserved." 35 | }, 36 | { 37 | "name": "Montserrat", 38 | "style": "normal", 39 | "weight": 400, 40 | "filename": "Montserrat-Regular.ttf", 41 | "postScriptName": "Montserrat-Regular", 42 | "fullName": "Montserrat", 43 | "copyright": "Copyright \u00a9 2014 by Julieta Ulanovsky. All rights reserved." 44 | }, 45 | { 46 | "name": "Montserrat", 47 | "style": "normal", 48 | "weight": 100, 49 | "filename": "Montserrat-Thin.ttf", 50 | "postScriptName": "Montserrat-Hairline", 51 | "fullName": "Montserrat Hairline", 52 | "copyright": "Copyright \u00a9 2014 by Julieta Ulanovsky. All rights reserved." 53 | } 54 | ], 55 | "subsets": [ 56 | "latin", 57 | "menu" 58 | ], 59 | "dateAdded": "2011-12-13" 60 | } 61 | -------------------------------------------------------------------------------- /example/github_search/fonts/montserrat/Montserrat-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/github_search/fonts/montserrat/Montserrat-Black.ttf -------------------------------------------------------------------------------- /example/github_search/fonts/montserrat/Montserrat-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/github_search/fonts/montserrat/Montserrat-Bold.ttf -------------------------------------------------------------------------------- /example/github_search/fonts/montserrat/Montserrat-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/github_search/fonts/montserrat/Montserrat-Light.ttf -------------------------------------------------------------------------------- /example/github_search/fonts/montserrat/Montserrat-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/github_search/fonts/montserrat/Montserrat-Regular.ttf -------------------------------------------------------------------------------- /example/github_search/fonts/montserrat/Montserrat-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/github_search/fonts/montserrat/Montserrat-Thin.ttf -------------------------------------------------------------------------------- /example/github_search/fonts/montserrat/OFL.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011-2012, Julieta Ulanovsky (julieta.ulanovsky@gmail.com), with Reserved Font Names 'Montserrat' 2 | 3 | This Font Software is licensed under the SIL Open Font License, Version 1.1. 4 | This license is copied below, and is also available with a FAQ at: 5 | http://scripts.sil.org/OFL 6 | 7 | 8 | ----------------------------------------------------------- 9 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 10 | ----------------------------------------------------------- 11 | 12 | PREAMBLE 13 | The goals of the Open Font License (OFL) are to stimulate worldwide 14 | development of collaborative font projects, to support the font creation 15 | efforts of academic and linguistic communities, and to provide a free and 16 | open framework in which fonts may be shared and improved in partnership 17 | with others. 18 | 19 | The OFL allows the licensed fonts to be used, studied, modified and 20 | redistributed freely as long as they are not sold by themselves. The 21 | fonts, including any derivative works, can be bundled, embedded, 22 | redistributed and/or sold with any software provided that any reserved 23 | names are not used by derivative works. The fonts and derivatives, 24 | however, cannot be released under any other type of license. The 25 | requirement for fonts to remain under this license does not apply 26 | to any document created using the fonts or their derivatives. 27 | 28 | DEFINITIONS 29 | "Font Software" refers to the set of files released by the Copyright 30 | Holder(s) under this license and clearly marked as such. This may 31 | include source files, build scripts and documentation. 32 | 33 | "Reserved Font Name" refers to any names specified as such after the 34 | copyright statement(s). 35 | 36 | "Original Version" refers to the collection of Font Software components as 37 | distributed by the Copyright Holder(s). 38 | 39 | "Modified Version" refers to any derivative made by adding to, deleting, 40 | or substituting -- in part or in whole -- any of the components of the 41 | Original Version, by changing formats or by porting the Font Software to a 42 | new environment. 43 | 44 | "Author" refers to any designer, engineer, programmer, technical 45 | writer or other person who contributed to the Font Software. 46 | 47 | PERMISSION & CONDITIONS 48 | Permission is hereby granted, free of charge, to any person obtaining 49 | a copy of the Font Software, to use, study, copy, merge, embed, modify, 50 | redistribute, and sell modified and unmodified copies of the Font 51 | Software, subject to the following conditions: 52 | 53 | 1) Neither the Font Software nor any of its individual components, 54 | in Original or Modified Versions, may be sold by itself. 55 | 56 | 2) Original or Modified Versions of the Font Software may be bundled, 57 | redistributed and/or sold with any software, provided that each copy 58 | contains the above copyright notice and this license. These can be 59 | included either as stand-alone text files, human-readable headers or 60 | in the appropriate machine-readable metadata fields within text or 61 | binary files as long as those fields can be easily viewed by the user. 62 | 63 | 3) No Modified Version of the Font Software may use the Reserved Font 64 | Name(s) unless explicit written permission is granted by the corresponding 65 | Copyright Holder. This restriction only applies to the primary font name as 66 | presented to the users. 67 | 68 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font 69 | Software shall not be used to promote, endorse or advertise any 70 | Modified Version, except to acknowledge the contribution(s) of the 71 | Copyright Holder(s) and the Author(s) or with their explicit written 72 | permission. 73 | 74 | 5) The Font Software, modified or unmodified, in part or in whole, 75 | must be distributed entirely under this license, and must not be 76 | distributed under any other license. The requirement for fonts to 77 | remain under this license does not apply to any document created 78 | using the Font Software. 79 | 80 | TERMINATION 81 | This license becomes null and void if any of the above conditions are 82 | not met. 83 | 84 | DISCLAIMER 85 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 86 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 87 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 88 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 89 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 90 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 91 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 92 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM 93 | OTHER DEALINGS IN THE FONT SOFTWARE. 94 | -------------------------------------------------------------------------------- /example/github_search/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/github_search/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/github_search/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /example/github_search/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /example/github_search/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/github_search/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/github_search/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/github_search/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/github_search/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/github_search/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/github_search/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/github_search/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/github_search/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/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /example/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /example/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /example/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /example/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /example/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /example/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /example/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /example/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /example/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /example/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /example/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /example/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /example/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /example/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/github_search/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /example/github_search/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/github_search/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/github_search/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /example/github_search/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/github_search/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /example/github_search/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/github_search/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /example/github_search/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/github_search/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/github_search/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/github_search/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 | github_search 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/github_search/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /example/github_search/lib/github_client.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:convert'; 3 | import 'dart:io'; 4 | 5 | import 'search_result.dart'; 6 | 7 | class GithubClient { 8 | final String baseUrl; 9 | final Map cache; 10 | final HttpClient client; 11 | 12 | GithubClient({ 13 | HttpClient? client, 14 | Map? cache, 15 | this.baseUrl = 'https://api.github.com/search/repositories?q=', 16 | }) : client = client ?? HttpClient(), 17 | cache = cache ?? {}; 18 | 19 | /// Search Github for repositories using the given term 20 | Future search(String term) async { 21 | if (term.isEmpty) { 22 | return SearchResult.noTerm(); 23 | } else if (cache.containsKey(term)) { 24 | return cache[term]!; 25 | } else { 26 | final result = await _fetchResults(term); 27 | 28 | cache[term] = result; 29 | 30 | return result; 31 | } 32 | } 33 | 34 | Future _fetchResults(String term) async { 35 | final request = await HttpClient().getUrl(Uri.parse('$baseUrl$term')); 36 | final response = await request.close(); 37 | final results = json.decode(await response.transform(utf8.decoder).join()) 38 | as Map; 39 | final items = (results['items'] as List).cast>(); 40 | 41 | return SearchResult.fromJson(items); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /example/github_search/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_redux/flutter_redux.dart'; 3 | import 'package:redux/redux.dart'; 4 | 5 | import 'github_client.dart'; 6 | import 'search_middleware.dart'; 7 | import 'search_reducer.dart'; 8 | import 'search_screen.dart'; 9 | import 'search_state.dart'; 10 | 11 | void main() { 12 | final store = Store( 13 | searchReducer, 14 | initialState: SearchInitial(), 15 | middleware: [ 16 | // The following middleware both achieve the same goal: Load search 17 | // results from github in response to SearchActions. 18 | // 19 | // One is implemented as a normal middleware, the other is implemented as 20 | // an epic for demonstration purposes. 21 | 22 | SearchMiddleware(GithubClient()), 23 | // EpicMiddleware(SearchEpic(GithubClient())), 24 | ], 25 | ); 26 | 27 | runApp(RxDartGithubSearchApp( 28 | store: store, 29 | )); 30 | } 31 | 32 | class RxDartGithubSearchApp extends StatelessWidget { 33 | final Store store; 34 | 35 | RxDartGithubSearchApp({Key? key, required this.store}) : super(key: key); 36 | 37 | @override 38 | Widget build(BuildContext context) { 39 | return StoreProvider( 40 | store: store, 41 | child: MaterialApp( 42 | title: 'RxDart Github Search', 43 | theme: ThemeData( 44 | brightness: Brightness.dark, 45 | primarySwatch: Colors.grey, 46 | ), 47 | home: SearchScreen(), 48 | ), 49 | ); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /example/github_search/lib/search_actions.dart: -------------------------------------------------------------------------------- 1 | import 'search_result.dart'; 2 | 3 | /// Actions 4 | class SearchAction { 5 | final String term; 6 | 7 | SearchAction(this.term); 8 | } 9 | 10 | class SearchEmptyAction {} 11 | 12 | class SearchLoadingAction {} 13 | 14 | class SearchErrorAction {} 15 | 16 | class SearchResultAction { 17 | final SearchResult result; 18 | 19 | SearchResultAction(this.result); 20 | } 21 | -------------------------------------------------------------------------------- /example/github_search/lib/search_empty_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class SearchEmptyView extends StatelessWidget { 4 | SearchEmptyView(); 5 | 6 | @override 7 | Widget build(BuildContext context) { 8 | return Container( 9 | alignment: FractionalOffset.center, 10 | child: Column( 11 | mainAxisAlignment: MainAxisAlignment.center, 12 | children: [ 13 | Icon( 14 | Icons.warning, 15 | color: Colors.yellow[200], 16 | size: 80.0, 17 | ), 18 | Container( 19 | padding: EdgeInsets.only(top: 16.0), 20 | child: Text( 21 | 'No results', 22 | style: TextStyle(color: Colors.yellow[100]), 23 | ), 24 | ) 25 | ], 26 | ), 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /example/github_search/lib/search_epic.dart: -------------------------------------------------------------------------------- 1 | import 'package:redux_epics/redux_epics.dart'; 2 | import 'package:rxdart/rxdart.dart'; 3 | 4 | import 'github_client.dart'; 5 | import 'search_actions.dart'; 6 | import 'search_state.dart'; 7 | 8 | /// The Search Epic provides the same functionality as the Search Middleware, 9 | /// but uses redux_epics and the RxDart package to perform the work. It will 10 | /// listen for Search Actions and perform the search after the user stop typing 11 | /// for 250ms. 12 | /// 13 | /// If a previous search was still loading, we will cancel the operation and 14 | /// fetch a set of results. This ensures only results for the latest search 15 | /// term are shown. 16 | class SearchEpic implements EpicClass { 17 | final GithubClient api; 18 | 19 | SearchEpic(this.api); 20 | 21 | @override 22 | Stream call(Stream actions, EpicStore store) { 23 | return actions 24 | // Narrow down to SearchAction actions 25 | .whereType() 26 | // Don't start searching until the user pauses for 250ms 27 | .debounce((_) => TimerStream(true, Duration(milliseconds: 250))) 28 | // Cancel the previous search and start a one with switchMap 29 | .switchMap((action) => _search(action.term)); 30 | } 31 | 32 | // Use the async* function to make our lives easier 33 | Stream _search(String term) async* { 34 | if (term.isEmpty) { 35 | yield SearchEmptyAction(); 36 | } else { 37 | // Dispatch a SearchLoadingAction to show a loading spinner 38 | yield SearchLoadingAction(); 39 | 40 | try { 41 | // If the api call is successful, dispatch the results for display 42 | yield SearchResultAction(await api.search(term)); 43 | } catch (e) { 44 | // If the search call fails, dispatch an error so we can show it 45 | yield SearchErrorAction(); 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /example/github_search/lib/search_error_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class SearchErrorWidget extends StatelessWidget { 4 | SearchErrorWidget(); 5 | 6 | @override 7 | Widget build(BuildContext context) { 8 | return Container( 9 | alignment: FractionalOffset.center, 10 | child: Column( 11 | mainAxisAlignment: MainAxisAlignment.center, 12 | crossAxisAlignment: CrossAxisAlignment.center, 13 | children: [ 14 | Icon(Icons.error_outline, color: Colors.red[300], size: 80.0), 15 | Container( 16 | padding: EdgeInsets.only(top: 16.0), 17 | child: Text( 18 | 'Rate limit exceeded', 19 | style: TextStyle( 20 | color: Colors.red[300], 21 | ), 22 | ), 23 | ) 24 | ], 25 | ), 26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /example/github_search/lib/search_initial_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class SearchInitialView extends StatelessWidget { 4 | SearchInitialView(); 5 | 6 | @override 7 | Widget build(BuildContext context) { 8 | return Container( 9 | alignment: FractionalOffset.center, 10 | child: Column( 11 | mainAxisAlignment: MainAxisAlignment.center, 12 | children: [ 13 | Icon(Icons.info, color: Colors.green[200], size: 80.0), 14 | Container( 15 | padding: EdgeInsets.only(top: 16.0), 16 | child: Text( 17 | 'Enter a search term to begin', 18 | style: TextStyle( 19 | color: Colors.green[100], 20 | ), 21 | ), 22 | ) 23 | ], 24 | ), 25 | ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /example/github_search/lib/search_loading_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class SearchLoadingView extends StatelessWidget { 4 | SearchLoadingView(); 5 | 6 | @override 7 | Widget build(BuildContext context) { 8 | return Container( 9 | alignment: FractionalOffset.center, 10 | child: CircularProgressIndicator(), 11 | ); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /example/github_search/lib/search_middleware.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:async/async.dart'; 4 | import 'package:redux/redux.dart'; 5 | 6 | import 'github_client.dart'; 7 | import 'search_actions.dart'; 8 | import 'search_state.dart'; 9 | 10 | /// The Search Middleware will listen for Search Actions and perform the search 11 | /// after the user stop typing for 250ms. 12 | /// 13 | /// If a previous search was still loading, we will cancel the operation and 14 | /// fetch a set of results. This ensures only results for the latest search 15 | /// term are shown. 16 | class SearchMiddleware implements MiddlewareClass { 17 | final GithubClient api; 18 | 19 | Timer? _timer; 20 | CancelableOperation>? _operation; 21 | 22 | SearchMiddleware(this.api); 23 | 24 | @override 25 | void call(Store store, dynamic action, NextDispatcher next) { 26 | if (action is SearchAction) { 27 | // Stop our previous debounce timer and search. 28 | _timer?.cancel(); 29 | _operation?.cancel(); 30 | 31 | // Don't start searching until the user pauses for 250ms. This will stop 32 | // us from over-fetching from our backend. 33 | _timer = Timer(Duration(milliseconds: 250), () { 34 | if (action.term.isEmpty) { 35 | store.dispatch(SearchEmptyAction()); 36 | } else { 37 | store.dispatch(SearchLoadingAction()); 38 | 39 | // Instead of a simple Future, we'll use a CancellableOperation from the 40 | // `async` package. This will allow us to cancel the previous operation 41 | // if a Search term comes in. This will prevent us from 42 | // accidentally showing stale results. 43 | _operation = CancelableOperation.fromFuture(api 44 | .search(action.term) 45 | .then((result) => store..dispatch(SearchResultAction(result))) 46 | .catchError((Object e, StackTrace s) => 47 | store..dispatch(SearchErrorAction()))); 48 | } 49 | }); 50 | } 51 | 52 | // Make sure to forward actions to the next middleware in the chain! 53 | next(action); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /example/github_search/lib/search_reducer.dart: -------------------------------------------------------------------------------- 1 | import 'package:redux/redux.dart'; 2 | 3 | import 'search_actions.dart'; 4 | import 'search_state.dart'; 5 | 6 | /// Reducer 7 | final searchReducer = combineReducers([ 8 | TypedReducer(_onEmpty), 9 | TypedReducer(_onLoad), 10 | TypedReducer(_onError), 11 | TypedReducer(_onResult), 12 | ]); 13 | 14 | SearchState _onEmpty(SearchState state, SearchEmptyAction action) => 15 | SearchInitial(); 16 | 17 | SearchState _onLoad(SearchState state, SearchLoadingAction action) => 18 | SearchLoading(); 19 | 20 | SearchState _onError(SearchState state, SearchErrorAction action) => 21 | SearchError(); 22 | 23 | SearchState _onResult(SearchState state, SearchResultAction action) => 24 | action.result.items.isEmpty 25 | ? SearchEmpty() 26 | : SearchPopulated(action.result); 27 | -------------------------------------------------------------------------------- /example/github_search/lib/search_result.dart: -------------------------------------------------------------------------------- 1 | enum SearchResultKind { noTerm, empty, populated } 2 | 3 | class SearchResult { 4 | final SearchResultKind kind; 5 | final List items; 6 | 7 | SearchResult(this.kind, this.items); 8 | 9 | factory SearchResult.noTerm() => 10 | SearchResult(SearchResultKind.noTerm, []); 11 | 12 | factory SearchResult.fromJson(List> list) { 13 | final items = [for (final item in list) SearchResultItem.fromJson(item)]; 14 | 15 | return SearchResult( 16 | items.isEmpty ? SearchResultKind.empty : SearchResultKind.populated, 17 | items, 18 | ); 19 | } 20 | 21 | bool get isPopulated => kind == SearchResultKind.populated; 22 | 23 | bool get isEmpty => kind == SearchResultKind.empty; 24 | 25 | bool get isNoTerm => kind == SearchResultKind.noTerm; 26 | } 27 | 28 | class SearchResultItem { 29 | final String fullName; 30 | final String url; 31 | final String avatarUrl; 32 | 33 | SearchResultItem(this.fullName, this.url, this.avatarUrl); 34 | 35 | factory SearchResultItem.fromJson(Map json) { 36 | return SearchResultItem( 37 | json['full_name'] as String, 38 | json['html_url'] as String, 39 | (json['owner'] as Map)['avatar_url'] as String, 40 | ); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /example/github_search/lib/search_result_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:transparent_image/transparent_image.dart'; 3 | 4 | import 'search_result.dart'; 5 | 6 | class SearchPopulatedView extends StatelessWidget { 7 | final SearchResult result; 8 | 9 | SearchPopulatedView(this.result); 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return ListView.builder( 14 | itemCount: result.items.length, 15 | itemBuilder: (context, index) { 16 | final item = result.items[index]; 17 | return _SearchItem(item: item); 18 | }, 19 | ); 20 | } 21 | 22 | void showItem(BuildContext context, SearchResultItem item) { 23 | Navigator.push( 24 | context, 25 | MaterialPageRoute( 26 | builder: (BuildContext context) { 27 | return Scaffold( 28 | resizeToAvoidBottomInset: false, 29 | body: GestureDetector( 30 | key: Key(item.avatarUrl), 31 | onTap: () => Navigator.pop(context), 32 | child: SizedBox.expand( 33 | child: Hero( 34 | tag: item.fullName, 35 | child: FadeInImage.memoryNetwork( 36 | fadeInDuration: Duration(milliseconds: 700), 37 | placeholder: kTransparentImage, 38 | image: item.avatarUrl, 39 | width: MediaQuery.of(context).size.width, 40 | height: 300.0, 41 | ), 42 | ), 43 | ), 44 | ), 45 | ); 46 | }, 47 | ), 48 | ); 49 | } 50 | } 51 | 52 | class _SearchItem extends StatelessWidget { 53 | const _SearchItem({ 54 | Key? key, 55 | required this.item, 56 | }) : super(key: key); 57 | 58 | final SearchResultItem item; 59 | 60 | @override 61 | Widget build(BuildContext context) { 62 | return InkWell( 63 | onTap: () { 64 | Navigator.push( 65 | context, 66 | MaterialPageRoute( 67 | builder: (BuildContext context) { 68 | return Scaffold( 69 | resizeToAvoidBottomInset: false, 70 | body: GestureDetector( 71 | key: Key(item.avatarUrl), 72 | onTap: () => Navigator.pop(context), 73 | child: SizedBox.expand( 74 | child: Hero( 75 | tag: item.fullName, 76 | child: Image.network( 77 | item.avatarUrl, 78 | width: MediaQuery.of(context).size.width, 79 | height: 300.0, 80 | ), 81 | ), 82 | ), 83 | ), 84 | ); 85 | }, 86 | ), 87 | ); 88 | }, 89 | child: Container( 90 | alignment: FractionalOffset.center, 91 | margin: EdgeInsets.fromLTRB(16.0, 12.0, 16.0, 12.0), 92 | child: Row( 93 | crossAxisAlignment: CrossAxisAlignment.start, 94 | children: [ 95 | Container( 96 | margin: EdgeInsets.only(right: 16.0), 97 | child: Hero( 98 | tag: item.fullName, 99 | child: ClipOval( 100 | child: Image.network( 101 | item.avatarUrl, 102 | width: 56.0, 103 | height: 56.0, 104 | ), 105 | ), 106 | ), 107 | ), 108 | Expanded( 109 | child: Column( 110 | crossAxisAlignment: CrossAxisAlignment.start, 111 | children: [ 112 | Container( 113 | margin: EdgeInsets.only( 114 | top: 6.0, 115 | bottom: 4.0, 116 | ), 117 | child: Text( 118 | '${item.fullName}', 119 | maxLines: 1, 120 | overflow: TextOverflow.ellipsis, 121 | style: TextStyle( 122 | fontFamily: 'Montserrat', 123 | fontSize: 16.0, 124 | fontWeight: FontWeight.bold, 125 | ), 126 | ), 127 | ), 128 | Container( 129 | child: Text( 130 | '${item.url}', 131 | style: TextStyle( 132 | fontFamily: 'Hind', 133 | ), 134 | maxLines: 1, 135 | overflow: TextOverflow.ellipsis, 136 | ), 137 | ) 138 | ], 139 | ), 140 | ) 141 | ], 142 | ), 143 | ), 144 | ); 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /example/github_search/lib/search_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_redux/flutter_redux.dart'; 3 | import 'package:github_search/search_empty_view.dart'; 4 | import 'package:github_search/search_error_view.dart'; 5 | import 'package:github_search/search_initial_view.dart'; 6 | import 'package:github_search/search_loading_view.dart'; 7 | import 'package:github_search/search_result_view.dart'; 8 | 9 | import 'search_actions.dart'; 10 | import 'search_state.dart'; 11 | 12 | class SearchScreen extends StatelessWidget { 13 | const SearchScreen({Key? key}) : super(key: key); 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return StoreConnector( 18 | converter: (store) { 19 | return _SearchScreenViewModel( 20 | state: store.state, 21 | onTextChanged: (term) => store.dispatch(SearchAction(term)), 22 | ); 23 | }, 24 | builder: (BuildContext context, _SearchScreenViewModel vm) { 25 | return Scaffold( 26 | body: Flex(direction: Axis.vertical, children: [ 27 | Container( 28 | padding: EdgeInsets.fromLTRB(16.0, 24.0, 16.0, 4.0), 29 | child: TextField( 30 | decoration: InputDecoration( 31 | border: InputBorder.none, 32 | hintText: 'Search Github...', 33 | ), 34 | style: TextStyle( 35 | fontSize: 36.0, 36 | fontFamily: 'Hind', 37 | decoration: TextDecoration.none, 38 | ), 39 | onChanged: vm.onTextChanged, 40 | ), 41 | ), 42 | Expanded( 43 | child: AnimatedSwitcher( 44 | duration: Duration(milliseconds: 500), 45 | child: _buildVisible(vm.state), 46 | ), 47 | ) 48 | ]), 49 | ); 50 | }, 51 | ); 52 | } 53 | 54 | Widget _buildVisible(SearchState state) { 55 | if (state is SearchLoading) { 56 | return SearchLoadingView(); 57 | } else if (state is SearchEmpty) { 58 | return SearchEmptyView(); 59 | } else if (state is SearchPopulated) { 60 | return SearchPopulatedView(state.result); 61 | } else if (state is SearchInitial) { 62 | return SearchInitialView(); 63 | } else if (state is SearchError) { 64 | return SearchErrorWidget(); 65 | } 66 | 67 | throw ArgumentError('No view for state: $state'); 68 | } 69 | } 70 | 71 | class _SearchScreenViewModel { 72 | final SearchState state; 73 | final void Function(String term) onTextChanged; 74 | 75 | _SearchScreenViewModel({required this.state, required this.onTextChanged}); 76 | } 77 | -------------------------------------------------------------------------------- /example/github_search/lib/search_state.dart: -------------------------------------------------------------------------------- 1 | // The State represents the data the View requires. The View consumes a Stream 2 | // of States. The view rebuilds every time the Stream emits a State! 3 | // 4 | // The State Stream will emit States depending on the situation: The 5 | // initial state, loading states, the list of results, and any errors that 6 | // happen. 7 | // 8 | // The State Stream responds to input from the View by accepting a 9 | // Stream. We call this Stream the onTextChanged "intent". 10 | import 'search_result.dart'; 11 | 12 | abstract class SearchState {} 13 | 14 | class SearchInitial implements SearchState {} 15 | 16 | class SearchLoading implements SearchState {} 17 | 18 | class SearchEmpty implements SearchState {} 19 | 20 | class SearchPopulated implements SearchState { 21 | final SearchResult result; 22 | 23 | SearchPopulated(this.result); 24 | } 25 | 26 | class SearchError implements SearchState {} 27 | -------------------------------------------------------------------------------- /example/github_search/linux/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral 2 | -------------------------------------------------------------------------------- /example/github_search/linux/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | project(runner LANGUAGES CXX) 3 | 4 | set(BINARY_NAME "github_search") 5 | set(APPLICATION_ID "com.example.github_search") 6 | 7 | cmake_policy(SET CMP0063 NEW) 8 | 9 | set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") 10 | 11 | # Configure build options. 12 | if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) 13 | set(CMAKE_BUILD_TYPE "Debug" CACHE 14 | STRING "Flutter build mode" FORCE) 15 | set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS 16 | "Debug" "Profile" "Release") 17 | endif() 18 | 19 | # Compilation settings that should be applied to most targets. 20 | function(APPLY_STANDARD_SETTINGS TARGET) 21 | target_compile_features(${TARGET} PUBLIC cxx_std_14) 22 | target_compile_options(${TARGET} PRIVATE -Wall -Werror) 23 | target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") 24 | target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") 25 | endfunction() 26 | 27 | set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") 28 | 29 | # Flutter library and tool build rules. 30 | add_subdirectory(${FLUTTER_MANAGED_DIR}) 31 | 32 | # System-level dependencies. 33 | find_package(PkgConfig REQUIRED) 34 | pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) 35 | 36 | add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") 37 | 38 | # Application build 39 | add_executable(${BINARY_NAME} 40 | "main.cc" 41 | "my_application.cc" 42 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" 43 | ) 44 | apply_standard_settings(${BINARY_NAME}) 45 | target_link_libraries(${BINARY_NAME} PRIVATE flutter) 46 | target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) 47 | add_dependencies(${BINARY_NAME} flutter_assemble) 48 | # Only the install-generated bundle's copy of the executable will launch 49 | # correctly, since the resources must in the right relative locations. To avoid 50 | # people trying to run the unbundled copy, put it in a subdirectory instead of 51 | # the default top-level location. 52 | set_target_properties(${BINARY_NAME} 53 | PROPERTIES 54 | RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" 55 | ) 56 | 57 | # Generated plugin build rules, which manage building the plugins and adding 58 | # them to the application. 59 | include(flutter/generated_plugins.cmake) 60 | 61 | 62 | # === Installation === 63 | # By default, "installing" just makes a relocatable bundle in the build 64 | # directory. 65 | set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") 66 | if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) 67 | set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) 68 | endif() 69 | 70 | # Start with a clean build bundle directory every time. 71 | install(CODE " 72 | file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") 73 | " COMPONENT Runtime) 74 | 75 | set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") 76 | set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") 77 | 78 | install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" 79 | COMPONENT Runtime) 80 | 81 | install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" 82 | COMPONENT Runtime) 83 | 84 | install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 85 | COMPONENT Runtime) 86 | 87 | if(PLUGIN_BUNDLED_LIBRARIES) 88 | install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" 89 | DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 90 | COMPONENT Runtime) 91 | endif() 92 | 93 | # Fully re-copy the assets directory on each build to avoid having stale files 94 | # from a previous install. 95 | set(FLUTTER_ASSET_DIR_NAME "flutter_assets") 96 | install(CODE " 97 | file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") 98 | " COMPONENT Runtime) 99 | install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" 100 | DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) 101 | 102 | # Install the AOT library on non-Debug builds only. 103 | if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") 104 | install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 105 | COMPONENT Runtime) 106 | endif() 107 | -------------------------------------------------------------------------------- /example/github_search/linux/flutter/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 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 | 11 | # Serves the same purpose as list(TRANSFORM ... PREPEND ...), 12 | # which isn't available in 3.10. 13 | function(list_prepend LIST_NAME PREFIX) 14 | set(NEW_LIST "") 15 | foreach(element ${${LIST_NAME}}) 16 | list(APPEND NEW_LIST "${PREFIX}${element}") 17 | endforeach(element) 18 | set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) 19 | endfunction() 20 | 21 | # === Flutter Library === 22 | # System-level dependencies. 23 | find_package(PkgConfig REQUIRED) 24 | pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) 25 | pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) 26 | pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) 27 | pkg_check_modules(BLKID REQUIRED IMPORTED_TARGET blkid) 28 | pkg_check_modules(LZMA REQUIRED IMPORTED_TARGET liblzma) 29 | 30 | set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") 31 | 32 | # Published to parent scope for install step. 33 | set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) 34 | set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) 35 | set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) 36 | set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) 37 | 38 | list(APPEND FLUTTER_LIBRARY_HEADERS 39 | "fl_basic_message_channel.h" 40 | "fl_binary_codec.h" 41 | "fl_binary_messenger.h" 42 | "fl_dart_project.h" 43 | "fl_engine.h" 44 | "fl_json_message_codec.h" 45 | "fl_json_method_codec.h" 46 | "fl_message_codec.h" 47 | "fl_method_call.h" 48 | "fl_method_channel.h" 49 | "fl_method_codec.h" 50 | "fl_method_response.h" 51 | "fl_plugin_registrar.h" 52 | "fl_plugin_registry.h" 53 | "fl_standard_message_codec.h" 54 | "fl_standard_method_codec.h" 55 | "fl_string_codec.h" 56 | "fl_value.h" 57 | "fl_view.h" 58 | "flutter_linux.h" 59 | ) 60 | list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") 61 | add_library(flutter INTERFACE) 62 | target_include_directories(flutter INTERFACE 63 | "${EPHEMERAL_DIR}" 64 | ) 65 | target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") 66 | target_link_libraries(flutter INTERFACE 67 | PkgConfig::GTK 68 | PkgConfig::GLIB 69 | PkgConfig::GIO 70 | PkgConfig::BLKID 71 | PkgConfig::LZMA 72 | ) 73 | add_dependencies(flutter flutter_assemble) 74 | 75 | # === Flutter tool backend === 76 | # _phony_ is a non-existent file to force this command to run every time, 77 | # since currently there's no way to get a full input/output list from the 78 | # flutter tool. 79 | add_custom_command( 80 | OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} 81 | ${CMAKE_CURRENT_BINARY_DIR}/_phony_ 82 | COMMAND ${CMAKE_COMMAND} -E env 83 | ${FLUTTER_TOOL_ENVIRONMENT} 84 | "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" 85 | linux-x64 ${CMAKE_BUILD_TYPE} 86 | VERBATIM 87 | ) 88 | add_custom_target(flutter_assemble DEPENDS 89 | "${FLUTTER_LIBRARY}" 90 | ${FLUTTER_LIBRARY_HEADERS} 91 | ) 92 | -------------------------------------------------------------------------------- /example/github_search/linux/flutter/generated_plugin_registrant.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | #include "generated_plugin_registrant.h" 6 | 7 | 8 | void fl_register_plugins(FlPluginRegistry* registry) { 9 | } 10 | -------------------------------------------------------------------------------- /example/github_search/linux/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 6 | #define GENERATED_PLUGIN_REGISTRANT_ 7 | 8 | #include 9 | 10 | // Registers Flutter plugins. 11 | void fl_register_plugins(FlPluginRegistry* registry); 12 | 13 | #endif // GENERATED_PLUGIN_REGISTRANT_ 14 | -------------------------------------------------------------------------------- /example/github_search/linux/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | ) 7 | 8 | set(PLUGIN_BUNDLED_LIBRARIES) 9 | 10 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 11 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) 12 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 13 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 14 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 15 | endforeach(plugin) 16 | -------------------------------------------------------------------------------- /example/github_search/linux/main.cc: -------------------------------------------------------------------------------- 1 | #include "my_application.h" 2 | 3 | int main(int argc, char** argv) { 4 | g_autoptr(MyApplication) app = my_application_new(); 5 | return g_application_run(G_APPLICATION(app), argc, argv); 6 | } 7 | -------------------------------------------------------------------------------- /example/github_search/linux/my_application.cc: -------------------------------------------------------------------------------- 1 | #include "my_application.h" 2 | 3 | #include 4 | #ifdef GDK_WINDOWING_X11 5 | #include 6 | #endif 7 | 8 | #include "flutter/generated_plugin_registrant.h" 9 | 10 | struct _MyApplication { 11 | GtkApplication parent_instance; 12 | char** dart_entrypoint_arguments; 13 | }; 14 | 15 | G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) 16 | 17 | // Implements GApplication::activate. 18 | static void my_application_activate(GApplication* application) { 19 | MyApplication* self = MY_APPLICATION(application); 20 | GtkWindow* window = 21 | GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); 22 | 23 | // Use a header bar when running in GNOME as this is the common style used 24 | // by applications and is the setup most users will be using (e.g. Ubuntu 25 | // desktop). 26 | // If running on X and not using GNOME then just use a traditional title bar 27 | // in case the window manager does more exotic layout, e.g. tiling. 28 | // If running on Wayland assume the header bar will work (may need changing 29 | // if future cases occur). 30 | gboolean use_header_bar = TRUE; 31 | #ifdef GDK_WINDOWING_X11 32 | GdkScreen *screen = gtk_window_get_screen(window); 33 | if (GDK_IS_X11_SCREEN(screen)) { 34 | const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); 35 | if (g_strcmp0(wm_name, "GNOME Shell") != 0) { 36 | use_header_bar = FALSE; 37 | } 38 | } 39 | #endif 40 | if (use_header_bar) { 41 | GtkHeaderBar *header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); 42 | gtk_widget_show(GTK_WIDGET(header_bar)); 43 | gtk_header_bar_set_title(header_bar, "github_search"); 44 | gtk_header_bar_set_show_close_button(header_bar, TRUE); 45 | gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); 46 | } 47 | else { 48 | gtk_window_set_title(window, "github_search"); 49 | } 50 | 51 | gtk_window_set_default_size(window, 1280, 720); 52 | gtk_widget_show(GTK_WIDGET(window)); 53 | 54 | g_autoptr(FlDartProject) project = fl_dart_project_new(); 55 | fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); 56 | 57 | FlView* view = fl_view_new(project); 58 | gtk_widget_show(GTK_WIDGET(view)); 59 | gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); 60 | 61 | fl_register_plugins(FL_PLUGIN_REGISTRY(view)); 62 | 63 | gtk_widget_grab_focus(GTK_WIDGET(view)); 64 | } 65 | 66 | // Implements GApplication::local_command_line. 67 | static gboolean my_application_local_command_line(GApplication* application, gchar ***arguments, int *exit_status) { 68 | MyApplication* self = MY_APPLICATION(application); 69 | // Strip out the first argument as it is the binary name. 70 | self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); 71 | 72 | g_autoptr(GError) error = nullptr; 73 | if (!g_application_register(application, nullptr, &error)) { 74 | g_warning("Failed to register: %s", error->message); 75 | *exit_status = 1; 76 | return TRUE; 77 | } 78 | 79 | g_application_activate(application); 80 | *exit_status = 0; 81 | 82 | return TRUE; 83 | } 84 | 85 | // Implements GObject::dispose. 86 | static void my_application_dispose(GObject *object) { 87 | MyApplication* self = MY_APPLICATION(object); 88 | g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); 89 | G_OBJECT_CLASS(my_application_parent_class)->dispose(object); 90 | } 91 | 92 | static void my_application_class_init(MyApplicationClass* klass) { 93 | G_APPLICATION_CLASS(klass)->activate = my_application_activate; 94 | G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; 95 | G_OBJECT_CLASS(klass)->dispose = my_application_dispose; 96 | } 97 | 98 | static void my_application_init(MyApplication* self) {} 99 | 100 | MyApplication* my_application_new() { 101 | return MY_APPLICATION(g_object_new(my_application_get_type(), 102 | "application-id", APPLICATION_ID, 103 | nullptr)); 104 | } 105 | -------------------------------------------------------------------------------- /example/github_search/linux/my_application.h: -------------------------------------------------------------------------------- 1 | #ifndef FLUTTER_MY_APPLICATION_H_ 2 | #define FLUTTER_MY_APPLICATION_H_ 3 | 4 | #include 5 | 6 | G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, 7 | GtkApplication) 8 | 9 | /** 10 | * my_application_new: 11 | * 12 | * Creates a new Flutter-based application. 13 | * 14 | * Returns: a new #MyApplication. 15 | */ 16 | MyApplication* my_application_new(); 17 | 18 | #endif // FLUTTER_MY_APPLICATION_H_ 19 | -------------------------------------------------------------------------------- /example/github_search/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: github_search 2 | description: A new flutter project. 3 | 4 | environment: 5 | sdk: ">=2.12.0 <3.0.0" 6 | 7 | dependencies: 8 | flutter: 9 | sdk: flutter 10 | redux: ^5.0.0 11 | flutter_redux: 12 | path: ../../ 13 | async: ^2.5.0 14 | redux_epics: ^0.15.0 15 | rxdart: ^0.26.0 16 | transparent_image: ^2.0.0 17 | 18 | dev_dependencies: 19 | pedantic: ^1.10.0 20 | 21 | 22 | # For information on the generic Dart part of this file, see the 23 | # following page: https://www.dartlang.org/tools/pub/pubspec 24 | 25 | # The following section is specific to Flutter. 26 | flutter: 27 | 28 | # The following line ensures that the Material Icons font is 29 | # included with your application, so that you can use the icons in 30 | # the Icons class. 31 | uses-material-design: true 32 | 33 | # To add assets to your application, add an assets section here, in 34 | # this "flutter" section, as in: 35 | # assets: 36 | # - images/a_dot_burr.jpeg 37 | # - images/a_dot_ham.jpeg 38 | 39 | # To add custom fonts to your application, add a fonts section here, 40 | # in this "flutter" section. Each entry in this list should have a 41 | # "family" key with the font family name, and a "fonts" key with a 42 | # list giving the asset and other descriptors for the font. For 43 | # example: 44 | fonts: 45 | - family: Montserrat 46 | fonts: 47 | - asset: fonts/montserrat/Montserrat-Bold.ttf 48 | - asset: fonts/montserrat/Montserrat-Regular.ttf 49 | - family: Hind 50 | fonts: 51 | - asset: fonts/hind/Hind-Regular.ttf 52 | -------------------------------------------------------------------------------- /example/github_search/web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/github_search/web/favicon.png -------------------------------------------------------------------------------- /example/github_search/web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/github_search/web/icons/Icon-192.png -------------------------------------------------------------------------------- /example/github_search/web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianegan/flutter_redux/4f32df61db8a140351e2c75d1154208bee7a21c0/example/github_search/web/icons/Icon-512.png -------------------------------------------------------------------------------- /example/github_search/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | github_search 30 | 31 | 32 | 33 | 36 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /example/github_search/web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "github_search", 3 | "short_name": "github_search", 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 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_redux 2 | description: A set of utility Widgets that Provide and Connect to a Redux Store 3 | version: 0.10.0 4 | homepage: https://github.com/brianegan/flutter_redux 5 | 6 | environment: 7 | sdk: ">=2.12.0 <3.0.0" 8 | 9 | dependencies: 10 | redux: ">=5.0.0 <6.0.0" 11 | flutter: 12 | sdk: flutter 13 | 14 | dev_dependencies: 15 | pedantic: ^1.10.0 16 | flutter_test: 17 | sdk: flutter 18 | mockito: ^5.0.0 19 | --------------------------------------------------------------------------------