├── .gitattributes
├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── dependabot.yaml
└── workflows
│ ├── auto_dependabot.yml
│ ├── ci.yml
│ ├── gh_pages_cleanup.yml
│ └── gh_pages_readme.yml
├── .gitignore
├── .metadata
├── .vscode
├── extensions.json
├── flutter.code-snippets
├── launch.json
└── tasks.json
├── CHANGELOG.md
├── LICENSE.md
├── README.md
├── analysis_options.yaml
├── android
├── .gitignore
├── app
│ ├── build.gradle
│ └── src
│ │ ├── debug
│ │ └── AndroidManifest.xml
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── kotlin
│ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── flutter_boolean_template
│ │ │ │ └── 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
├── bricks
└── feature_riverpod_architecture
│ ├── CHANGELOG.md
│ ├── LICENSE
│ ├── README.md
│ ├── __brick__
│ └── {{feature_name.snakeCase()}}
│ │ ├── application
│ │ └── application.dart
│ │ ├── data
│ │ ├── data_source
│ │ │ └── weather_api.dart
│ │ ├── dto
│ │ │ ├── weather.dart
│ │ │ └── weather.mapper.dart
│ │ └── repository
│ │ │ ├── repository_providers.dart
│ │ │ ├── repository_providers.g.dart
│ │ │ └── weather_repository.dart
│ │ ├── domain
│ │ ├── entity
│ │ │ ├── user_account.dart
│ │ │ ├── user_account.freezed.dart
│ │ │ └── user_account.modddel.dart
│ │ └── value
│ │ │ ├── email.dart
│ │ │ ├── email.freezed.dart
│ │ │ ├── email.modddel.dart
│ │ │ ├── id.dart
│ │ │ ├── id.freezed.dart
│ │ │ ├── id.modddel.dart
│ │ │ ├── name.dart
│ │ │ ├── name.freezed.dart
│ │ │ └── name.modddel.dart
│ │ └── presentation
│ │ └── feature_first_widget.dart
│ └── brick.yaml
├── codecov.yml
├── codemagic.yaml
├── dart_test.yaml
├── devtools_options.yaml
├── docs
├── CI.md
├── creating_bricks.png
└── example_layers.webp
├── flutter_native_splash.yaml
├── integration_test
└── example_test.dart
├── ios
├── .gitignore
├── Flutter
│ ├── AppFrameworkInfo.plist
│ ├── Debug.xcconfig
│ └── Release.xcconfig
├── Podfile
├── Runner.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ └── WorkspaceSettings.xcsettings
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
├── Runner.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
├── app.dart
├── main.dart
├── src
│ ├── common
│ │ ├── exceptions
│ │ │ └── app_exeption.dart
│ │ └── widgets
│ │ │ ├── animated_fade_switcher.dart
│ │ │ ├── blank.dart
│ │ │ ├── constrained_scrollable_child.dart
│ │ │ └── prototype_height.dart
│ ├── features
│ │ ├── books
│ │ │ └── presentation
│ │ │ │ ├── book_details_screen.dart
│ │ │ │ └── books_screen.dart
│ │ ├── connectivity
│ │ │ └── presentation
│ │ │ │ ├── connectivity_builder.dart
│ │ │ │ └── offline_warning_widget.dart
│ │ ├── example_feature
│ │ │ ├── application
│ │ │ │ └── application.dart
│ │ │ ├── data
│ │ │ │ ├── data_source
│ │ │ │ │ └── weather_api.dart
│ │ │ │ ├── dto
│ │ │ │ │ ├── weather.dart
│ │ │ │ │ └── weather.mapper.dart
│ │ │ │ └── repository
│ │ │ │ │ ├── repository_providers.dart
│ │ │ │ │ ├── repository_providers.g.dart
│ │ │ │ │ └── weather_repository.dart
│ │ │ ├── domain
│ │ │ │ ├── entity
│ │ │ │ │ ├── user_account.dart
│ │ │ │ │ ├── user_account.freezed.dart
│ │ │ │ │ └── user_account.modddel.dart
│ │ │ │ └── value
│ │ │ │ │ ├── email.dart
│ │ │ │ │ ├── email.freezed.dart
│ │ │ │ │ ├── email.modddel.dart
│ │ │ │ │ ├── id.dart
│ │ │ │ │ ├── id.freezed.dart
│ │ │ │ │ ├── id.modddel.dart
│ │ │ │ │ ├── name.dart
│ │ │ │ │ ├── name.freezed.dart
│ │ │ │ │ └── name.modddel.dart
│ │ │ └── presentation
│ │ │ │ └── feature_first_widget.dart
│ │ ├── initialization
│ │ │ ├── application
│ │ │ │ ├── app_startup.dart
│ │ │ │ ├── app_startup.g.dart
│ │ │ │ ├── info_service.dart
│ │ │ │ └── info_service.g.dart
│ │ │ └── presentation
│ │ │ │ └── app_startup_widget.dart
│ │ ├── profile
│ │ │ └── presentation
│ │ │ │ ├── profile_details_screen.dart
│ │ │ │ └── profile_screen.dart
│ │ └── settings
│ │ │ ├── application
│ │ │ ├── settings_service.dart
│ │ │ ├── settings_service.g.dart
│ │ │ ├── themes.dart
│ │ │ └── themes.g.dart
│ │ │ ├── data
│ │ │ ├── dto
│ │ │ │ ├── flex_scheme_data.dart
│ │ │ │ ├── human_name_enum.dart
│ │ │ │ ├── navigation_type_override.dart
│ │ │ │ ├── navigation_type_override.g.dart
│ │ │ │ ├── navigation_type_override.mapper.dart
│ │ │ │ ├── settings.dart
│ │ │ │ ├── settings.g.dart
│ │ │ │ ├── settings.mapper.dart
│ │ │ │ ├── theme_type.dart
│ │ │ │ ├── theme_type.g.dart
│ │ │ │ └── theme_type.mapper.dart
│ │ │ └── repository
│ │ │ │ ├── settings_repository.dart
│ │ │ │ └── settings_repository.g.dart
│ │ │ └── presentation
│ │ │ ├── extensions.dart
│ │ │ ├── screens
│ │ │ ├── about_settings_screen.dart
│ │ │ ├── appearance_settings_screen.dart
│ │ │ ├── settings_screen.dart
│ │ │ └── unknown_settings_screen.dart
│ │ │ ├── utils.dart
│ │ │ └── widgets
│ │ │ ├── app_settings.dart
│ │ │ ├── segmented_button_tile.dart
│ │ │ └── theme_selector_tile.dart
│ ├── routing
│ │ ├── application
│ │ │ ├── location_history_notifier.dart
│ │ │ └── location_notifier.dart
│ │ ├── data
│ │ │ ├── location_history.dart
│ │ │ ├── location_history.mapper.dart
│ │ │ └── navigation_type.dart
│ │ ├── presentation
│ │ │ ├── routes
│ │ │ │ ├── book_details_route.dart
│ │ │ │ ├── books_route.dart
│ │ │ │ ├── profile_details_route.dart
│ │ │ │ ├── profile_route.dart
│ │ │ │ ├── setting_details_route.dart
│ │ │ │ └── settings_route.dart
│ │ │ └── widgets
│ │ │ │ ├── auto_leading_button.dart
│ │ │ │ ├── implicitly_animated_page_switcher.dart
│ │ │ │ ├── responsive_scaffold.dart
│ │ │ │ ├── responsive_sidebar.dart
│ │ │ │ ├── root_scaffold_shell.dart
│ │ │ │ └── router_widget.dart
│ │ └── router
│ │ │ ├── router.dart
│ │ │ └── router_extensions.dart
│ └── store
│ │ └── store_example.dart
└── utils
│ └── utils.dart
├── linux
├── .gitignore
├── CMakeLists.txt
├── appimage
│ ├── AppRun.desktop
│ └── AppRun.png
├── flutter
│ └── CMakeLists.txt
├── main.cc
├── my_application.cc
└── my_application.h
├── macos
├── .gitignore
├── Flutter
│ ├── Flutter-Debug.xcconfig
│ └── Flutter-Release.xcconfig
├── Podfile
├── Runner.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── Runner
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ └── AppIcon.appiconset
│ │ ├── Contents.json
│ │ ├── app_icon_1024.png
│ │ ├── app_icon_128.png
│ │ ├── app_icon_16.png
│ │ ├── app_icon_256.png
│ │ ├── app_icon_32.png
│ │ ├── app_icon_512.png
│ │ └── app_icon_64.png
│ ├── Base.lproj
│ └── MainMenu.xib
│ ├── Configs
│ ├── AppInfo.xcconfig
│ ├── Debug.xcconfig
│ ├── Release.xcconfig
│ └── Warnings.xcconfig
│ ├── DebugProfile.entitlements
│ ├── Info.plist
│ ├── MainFlutterWindow.swift
│ └── Release.entitlements
├── mason.yaml
├── melos.yaml
├── packages
├── app_lints
│ ├── lib
│ │ └── analysis_options.yaml
│ ├── pubspec.lock
│ └── pubspec.yaml
├── assets
│ ├── .metadata
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── analysis_options.yaml
│ ├── lib
│ │ ├── assets.dart
│ │ ├── images
│ │ │ └── flutter_logo.png
│ │ └── src
│ │ │ ├── asset.dart
│ │ │ └── assets.dart
│ ├── pubspec.lock
│ ├── pubspec.yaml
│ └── test
│ │ └── assets_test.dart
├── constants
│ ├── .gitignore
│ ├── .metadata
│ ├── CHANGELOG.md
│ ├── LICENSE
│ ├── README.md
│ ├── analysis_options.yaml
│ ├── lib
│ │ ├── constants.dart
│ │ └── src
│ │ │ ├── flavor.dart
│ │ │ ├── strings.dart
│ │ │ └── widgets.dart
│ ├── pubspec.yaml
│ └── test
│ │ └── constants_test.dart
├── env
│ ├── .metadata
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── analysis_options.yaml
│ ├── dev.env.example
│ ├── lib
│ │ ├── env.dart
│ │ └── src
│ │ │ └── env
│ │ │ ├── config
│ │ │ ├── env_fields.dart
│ │ │ └── env_flavor.dart
│ │ │ ├── dev_env.dart
│ │ │ ├── local_env.dart
│ │ │ ├── prod_env.dart
│ │ │ └── staging_env.dart
│ ├── local.env.example
│ ├── prod.env.example
│ ├── pubspec.lock
│ ├── pubspec.yaml
│ ├── staging.env.example
│ └── test
│ │ └── env_test.dart
├── localization
│ ├── .metadata
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── analysis_options.yaml
│ ├── l10n.yaml
│ ├── lib
│ │ ├── localization.dart
│ │ └── src
│ │ │ ├── app_localizations_context.dart
│ │ │ ├── app_localizations_provider.dart
│ │ │ ├── localization
│ │ │ ├── app_localizations.dart
│ │ │ └── app_localizations_en.dart
│ │ │ └── translations
│ │ │ └── app_en.arb
│ ├── pubspec.lock
│ ├── pubspec.yaml
│ └── test
│ │ ├── ensure_build_test.dart
│ │ └── localization_test.dart
├── log
│ ├── .gitignore
│ ├── .metadata
│ ├── CHANGELOG.md
│ ├── LICENSE
│ ├── README.md
│ ├── analysis_options.yaml
│ ├── lib
│ │ ├── log.dart
│ │ └── src
│ │ │ ├── log_config.dart
│ │ │ └── log_widget.dart
│ ├── pubspec.yaml
│ └── test
│ │ └── main_test.dart
└── pub
│ ├── pagination
│ ├── .gitignore
│ ├── .metadata
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── analysis_options.yaml
│ ├── lib
│ │ ├── pagination.dart
│ │ └── src
│ │ │ └── paginated_view.dart
│ └── pubspec.yaml
│ ├── pagination_dart
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── analysis_options.yaml
│ ├── lib
│ │ ├── pagination_dart.dart
│ │ └── src
│ │ │ ├── keep_alive_duration.dart
│ │ │ └── paginated_result.dart
│ └── pubspec.yaml
│ └── sidebarx
│ ├── .gitignore
│ ├── .metadata
│ ├── CHANGELOG.md
│ ├── CODE_OF_CONDUCT.md
│ ├── CONTRIBUTING.md
│ ├── LICENSE
│ ├── README.md
│ ├── analysis_options.yaml
│ ├── example
│ ├── .gitignore
│ ├── .metadata
│ ├── README.md
│ ├── analysis_options.yaml
│ ├── android
│ │ ├── .gitignore
│ │ ├── app
│ │ │ ├── build.gradle
│ │ │ └── src
│ │ │ │ ├── debug
│ │ │ │ └── AndroidManifest.xml
│ │ │ │ ├── main
│ │ │ │ ├── AndroidManifest.xml
│ │ │ │ ├── kotlin
│ │ │ │ │ └── com
│ │ │ │ │ │ └── example
│ │ │ │ │ │ └── example
│ │ │ │ │ │ └── MainActivity.kt
│ │ │ │ └── res
│ │ │ │ │ ├── drawable-v21
│ │ │ │ │ └── launch_background.xml
│ │ │ │ │ ├── drawable
│ │ │ │ │ └── launch_background.xml
│ │ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ │ ├── values-night
│ │ │ │ │ └── styles.xml
│ │ │ │ │ └── values
│ │ │ │ │ └── styles.xml
│ │ │ │ └── profile
│ │ │ │ └── AndroidManifest.xml
│ │ ├── build.gradle
│ │ ├── gradle.properties
│ │ ├── gradle
│ │ │ └── wrapper
│ │ │ │ └── gradle-wrapper.properties
│ │ └── settings.gradle
│ ├── assets
│ │ └── images
│ │ │ └── avatar.png
│ ├── 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
│ │ ├── desktop_example.dart
│ │ ├── example_mobile.dart
│ │ └── main.dart
│ ├── linux
│ │ ├── .gitignore
│ │ ├── CMakeLists.txt
│ │ ├── flutter
│ │ │ └── CMakeLists.txt
│ │ ├── main.cc
│ │ ├── my_application.cc
│ │ └── my_application.h
│ ├── macos
│ │ ├── .gitignore
│ │ ├── Flutter
│ │ │ ├── Flutter-Debug.xcconfig
│ │ │ └── Flutter-Release.xcconfig
│ │ ├── Runner.xcodeproj
│ │ │ ├── project.pbxproj
│ │ │ ├── project.xcworkspace
│ │ │ │ └── xcshareddata
│ │ │ │ │ └── IDEWorkspaceChecks.plist
│ │ │ └── xcshareddata
│ │ │ │ └── xcschemes
│ │ │ │ └── Runner.xcscheme
│ │ ├── Runner.xcworkspace
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcshareddata
│ │ │ │ └── IDEWorkspaceChecks.plist
│ │ └── Runner
│ │ │ ├── AppDelegate.swift
│ │ │ ├── Assets.xcassets
│ │ │ └── AppIcon.appiconset
│ │ │ │ ├── Contents.json
│ │ │ │ ├── app_icon_1024.png
│ │ │ │ ├── app_icon_128.png
│ │ │ │ ├── app_icon_16.png
│ │ │ │ ├── app_icon_256.png
│ │ │ │ ├── app_icon_32.png
│ │ │ │ ├── app_icon_512.png
│ │ │ │ └── app_icon_64.png
│ │ │ ├── Base.lproj
│ │ │ └── MainMenu.xib
│ │ │ ├── Configs
│ │ │ ├── AppInfo.xcconfig
│ │ │ ├── Debug.xcconfig
│ │ │ ├── Release.xcconfig
│ │ │ └── Warnings.xcconfig
│ │ │ ├── DebugProfile.entitlements
│ │ │ ├── Info.plist
│ │ │ ├── MainFlutterWindow.swift
│ │ │ └── Release.entitlements
│ ├── pubspec.lock
│ ├── pubspec.yaml
│ ├── repo
│ │ ├── example.gif
│ │ ├── example_mobile_small.gif
│ │ └── example_web.gif
│ ├── web
│ │ ├── favicon.png
│ │ ├── icons
│ │ │ ├── Icon-192.png
│ │ │ ├── Icon-512.png
│ │ │ ├── Icon-maskable-192.png
│ │ │ └── Icon-maskable-512.png
│ │ ├── index.html
│ │ └── manifest.json
│ └── windows
│ │ ├── .gitignore
│ │ ├── CMakeLists.txt
│ │ ├── flutter
│ │ └── CMakeLists.txt
│ │ └── runner
│ │ ├── CMakeLists.txt
│ │ ├── Runner.rc
│ │ ├── flutter_window.cpp
│ │ ├── flutter_window.h
│ │ ├── main.cpp
│ │ ├── resource.h
│ │ ├── resources
│ │ └── app_icon.ico
│ │ ├── runner.exe.manifest
│ │ ├── utils.cpp
│ │ ├── utils.h
│ │ ├── win32_window.cpp
│ │ └── win32_window.h
│ ├── lib
│ ├── sidebarx.dart
│ └── src
│ │ ├── controller
│ │ ├── controller.dart
│ │ └── sidebarx_controller.dart
│ │ ├── models
│ │ ├── models.dart
│ │ └── sidebarx_item.dart
│ │ ├── sidebarx_base.dart
│ │ ├── src.dart
│ │ ├── theme
│ │ ├── sidebarx_theme.dart
│ │ └── theme.dart
│ │ ├── utils
│ │ ├── types.dart
│ │ └── utils.dart
│ │ └── widgets
│ │ ├── sidebarx_cell.dart
│ │ └── widgets.dart
│ ├── pubspec.yaml
│ └── test
│ ├── controller_test.dart
│ ├── sidebarx_base_test.dart
│ └── test_sidebarx_widget.dart
├── pubspec.lock
├── pubspec.yaml
├── test
├── ensure_build_test.dart
└── main_test.dart
├── web
├── favicon.png
├── icons
│ ├── Icon-192.png
│ ├── Icon-512.png
│ ├── Icon-maskable-192.png
│ └── Icon-maskable-512.png
├── index.html
└── manifest.json
└── windows
├── .gitignore
├── CMakeLists.txt
├── flutter
└── CMakeLists.txt
└── runner
├── CMakeLists.txt
├── Runner.rc
├── flutter_window.cpp
├── flutter_window.h
├── main.cpp
├── resource.h
├── resources
└── app_icon.ico
├── runner.exe.manifest
├── utils.cpp
├── utils.h
├── win32_window.cpp
└── win32_window.h
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Generated files
5 | **/*.g.dart linguist-generated=true
6 | **/*.mapper.dart linguist-generated=true
7 | **/*.modddel.dart linguist-generated=true
8 | **/*.iconfig.dart linguist-generated=true
9 | **/i18n.dart linguist-generated=true
10 | lib/generated/intl/messages*.dart linguist-generated=true
11 | **/*.chopper.dart linguist-generated=true
12 | **/*.swagger.dart linguist-generated=true
13 | **/client_mapping.dart linguist-generated=true
14 | **/*.auto_mappr.dart linguist-generated=true
15 | **/*.lock linguist-generated=true
16 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - OS: [e.g. iOS]
28 | - Browser [e.g. chrome, safari]
29 | - Version [e.g. 22]
30 |
31 | **Smartphone (please complete the following information):**
32 | - Device: [e.g. iPhone6]
33 | - OS: [e.g. iOS8.1]
34 | - Browser [e.g. stock browser, safari]
35 | - Version [e.g. 22]
36 |
37 | **Additional context**
38 | Add any other context about the problem here.
39 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.github/dependabot.yaml:
--------------------------------------------------------------------------------
1 | version: 2
2 | enable-beta-ecosystems: true
3 | updates:
4 | - package-ecosystem: "pub"
5 | directory: "/"
6 | schedule:
7 | interval: "daily"
--------------------------------------------------------------------------------
/.github/workflows/auto_dependabot.yml:
--------------------------------------------------------------------------------
1 | name: Automate Dependabot
2 | on: pull_request
3 |
4 | permissions:
5 | contents: write
6 | pull-requests: write
7 |
8 | jobs:
9 | dependabot:
10 | runs-on: ubuntu-latest
11 | if: github.actor == 'dependabot[bot]'
12 | steps:
13 | - name: Fetch Dependabot metadata
14 | id: metadata
15 | uses: dependabot/fetch-metadata@v1
16 | with:
17 | github-token: "${{ secrets.GITHUB_TOKEN }}"
18 | - name: Approve PR
19 | run: gh pr review --approve "$PR_URL"
20 | env:
21 | PR_URL: ${{github.event.pull_request.html_url}}
22 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
23 | GH_TOKEN: ${{secrets.PAT}}
24 | - name: Enable auto-merge for patch updates
25 | if: steps.metadata.outputs.update-type == 'version-update:semver-patch'
26 | run: gh pr merge --auto --merge "$PR_URL"
27 | env:
28 | PR_URL: ${{github.event.pull_request.html_url}}
29 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
30 |
--------------------------------------------------------------------------------
/.github/workflows/gh_pages_cleanup.yml:
--------------------------------------------------------------------------------
1 | name: gh-pages-cleanup
2 | on: delete
3 |
4 | jobs:
5 | cleanup:
6 | name: Cleanup gh-pages
7 | runs-on: ubuntu-latest
8 | if: github.event.ref_type == 'branch'
9 | steps:
10 | - name: Checkout
11 | uses: actions/checkout@v4
12 | env:
13 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
14 | with:
15 | lfs: true
16 | ref: gh-pages
17 | persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal access token.
18 | fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository.
19 | - name: Get branch name
20 | id: branch-name
21 | uses: tj-actions/branch-names@v8
22 | - name: Remove deleted branch from gh-pages
23 | if: steps.branch-name.outputs.is_default == 'true'
24 | run: |
25 | git config user.name "Github Actions"
26 | git config user.email github-actions@github.com
27 |
28 | BASE_REF=$(printf "%q" "${{ github.event.ref }}")
29 | BASE_REF=${BASE_REF/refs\/heads\/}
30 |
31 | if test -d "$BASE_REF"; then
32 | echo "Deleting folder: $BASE_REF"
33 | git rm -rf "$BASE_REF"
34 | git commit -m "Remove deleted branch"
35 | else
36 | echo "Folder $BASE_REF does not exist"
37 | fi
38 | - name: Push changes
39 | uses: ad-m/github-push-action@v0.8.0
40 | with:
41 | # PAT required to trigger gh_pages_readme.yml workflow
42 | github_token: ${{ secrets.PAT }}
43 | branch: gh-pages
44 |
--------------------------------------------------------------------------------
/.github/workflows/gh_pages_readme.yml:
--------------------------------------------------------------------------------
1 | # CI to generate an README.md file for GitHub Pages for each branch's subfolder in the gh-pages branch
2 |
3 | name: gh_pages_readme
4 |
5 | on:
6 | workflow_dispatch:
7 | push:
8 | branches:
9 | - "gh-pages"
10 |
11 | jobs:
12 | gh_pages_readme:
13 | runs-on: ubuntu-latest
14 | steps:
15 | - uses: actions/checkout@v4
16 | with:
17 | fetch-depth: 0
18 | ref: gh-pages
19 | # Delete README.md
20 | - name: Delete README.md
21 | run: rm -f README.md
22 | # get list of branches and generate links to each branch's subfolder in the README.md file
23 | - name: Generate README.md
24 | run: |
25 | echo "## Flutter Branch Web Previews" >> README.md
26 | echo "" >> README.md
27 | git branch -r | grep -v '\->' | grep -v 'origin/gh-pages' | while read remote; do git branch --track "${remote#origin/}" "$remote"; done
28 | for branch in `git branch -r | grep -v '\->' | grep -v 'origin/gh-pages'`; do echo "- [${branch#origin/}](./${branch#origin/}/)" >> README.md; done
29 | - name: Commit and push if changed
30 | run: |
31 | git config --global user.name 'GitHub Actions'
32 | git config --global user.email github-actions@github.com
33 | git add README.md
34 | git diff-index --quiet HEAD || git commit -m 'Update README.md'
35 | git push
36 |
--------------------------------------------------------------------------------
/.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: "d211f42860350d914a5ad8102f9ec32764dc6d06"
8 | channel: "stable"
9 |
10 | project_type: app
11 |
12 | # Tracks metadata for the flutter migrate command
13 | migration:
14 | platforms:
15 | - platform: root
16 | create_revision: d211f42860350d914a5ad8102f9ec32764dc6d06
17 | base_revision: d211f42860350d914a5ad8102f9ec32764dc6d06
18 | - platform: windows
19 | create_revision: d211f42860350d914a5ad8102f9ec32764dc6d06
20 | base_revision: d211f42860350d914a5ad8102f9ec32764dc6d06
21 |
22 | # User provided section
23 |
24 | # List of Local paths (relative to this file) that should be
25 | # ignored by the migrate tool.
26 | #
27 | # Files that are not part of the templates will be ignored by default.
28 | unmanaged_files:
29 | - 'lib/main.dart'
30 | - 'ios/Runner.xcodeproj/project.pbxproj'
31 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "robert-brunhage.flutter-riverpod-snippets",
4 | "dart-code.flutter",
5 | "dart-code.dart-code",
6 | "felixangelov.mason",
7 | "ryanluker.vscode-coverage-gutters",
8 | "jeroen-meijer.pubspec-assist",
9 | "usernamehw.remove-empty-lines",
10 | "albert.tabout",
11 | "pflannery.vscode-versionlens",
12 | "gruntfuggly.todo-tree",
13 | "redhat.vscode-yaml",
14 | "blaugold.melos-code",
15 | "peterschmalfeldt.explorer-exclude",
16 | "irongeek.vscode-env"
17 | ]
18 | }
--------------------------------------------------------------------------------
/.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": "debug mode",
9 | "request": "launch",
10 | "type": "dart",
11 | "program": "lib/main.dart",
12 | "args": [
13 | "--dart-define",
14 | "FLUTTER_APP_FLAVOR=local"
15 | ]
16 | },
17 | {
18 | "name": "profile mode",
19 | "request": "launch",
20 | "type": "dart",
21 | "flutterMode": "profile",
22 | "program": "lib/main.dart",
23 | "args": [
24 | "--dart-define",
25 | "FLUTTER_APP_FLAVOR=local"
26 | ]
27 | },
28 | {
29 | "name": "release mode",
30 | "request": "launch",
31 | "type": "dart",
32 | "flutterMode": "release",
33 | "program": "lib/main.dart",
34 | "args": [
35 | "--dart-define",
36 | "FLUTTER_APP_FLAVOR=local"
37 | ]
38 | }
39 | ]
40 | }
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0.0",
3 | "tasks": [
4 | {
5 | "type": "melos",
6 | "script": "test",
7 | "label": "melos: test"
8 | }
9 | ]
10 | }
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | All notable changes to this project will be documented in this file.
4 |
5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7 |
8 | ## [Unreleased]
9 |
10 | ### Added
11 |
12 | - Add `CHANGELOG.md` file.
13 |
14 | ### Changed
15 |
16 | - Add changes here
17 |
18 | ### Fixed
19 |
20 | - Add bug fixes here
21 |
22 | ### Removed
23 |
24 | - Add anything removed here
25 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | Copyright © 2023, 2024 @getBoolean
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 |
6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 |
8 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 |
--------------------------------------------------------------------------------
/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | include: package:app_lints/analysis_options.yaml
2 |
3 | custom_lint:
4 | rules:
5 | - avoid_late_keyword: false
6 | - avoid_using_api:
7 | entries:
8 | - class_name: EdgeInsets
9 | source: package:flutter
10 | reason: Use `EdgeInsetsDirectional` instead.
11 | - class_name: Positioned
12 | source: package:flutter
13 | reason: Use `PositionedDirectional` instead.
14 | - class_name: Alignment
15 | source: package:flutter
16 | reason: Use `AlignmentDirectional` instead.
17 | # TODO: Implement lint only Border() constructor
18 | - class_name: Border
19 | source: package:flutter
20 | reason: Use `BorderDirectional` instead.
21 | - class_name: BorderRadius
22 | source: package:flutter
23 | reason: Use `BorderRadiusDirectional` instead.
24 |
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
9 | # Remember to never publicly share your keystore.
10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
11 | key.properties
12 | **/*.keystore
13 | **/*.jks
14 |
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/com/example/flutter_boolean_template/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.example.flutter_boolean_template
2 |
3 | import io.flutter.embedding.android.FlutterActivity
4 |
5 | class MainActivity: FlutterActivity()
6 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-v21/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getBoolean/flutter_boolean_template/5ebb31262d732441601fba7785ae863ca34a24d0/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getBoolean/flutter_boolean_template/5ebb31262d732441601fba7785ae863ca34a24d0/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getBoolean/flutter_boolean_template/5ebb31262d732441601fba7785ae863ca34a24d0/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getBoolean/flutter_boolean_template/5ebb31262d732441601fba7785ae863ca34a24d0/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getBoolean/flutter_boolean_template/5ebb31262d732441601fba7785ae863ca34a24d0/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.9.22'
3 | repositories {
4 | google()
5 | mavenCentral()
6 | }
7 |
8 | dependencies {
9 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
10 | }
11 | }
12 |
13 | allprojects {
14 | repositories {
15 | google()
16 | mavenCentral()
17 | }
18 | }
19 |
20 | rootProject.buildDir = '../build'
21 | subprojects {
22 | project.buildDir = "${rootProject.buildDir}/${project.name}"
23 | }
24 | subprojects {
25 | project.evaluationDependsOn(':app')
26 | }
27 |
28 | tasks.register("clean", Delete) {
29 | delete rootProject.buildDir
30 | }
31 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.useAndroidX=true
3 | android.enableJetifier=true
4 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | zipStoreBase=GRADLE_USER_HOME
4 | zipStorePath=wrapper/dists
5 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
6 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | def flutterSdkPath = {
3 | def properties = new Properties()
4 | file("local.properties").withInputStream { properties.load(it) }
5 | def flutterSdkPath = properties.getProperty("flutter.sdk")
6 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
7 | return flutterSdkPath
8 | }
9 | settings.ext.flutterSdkPath = flutterSdkPath()
10 |
11 | includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")
12 |
13 | repositories {
14 | google()
15 | mavenCentral()
16 | gradlePluginPortal()
17 | }
18 |
19 | plugins {
20 | id "dev.flutter.flutter-gradle-plugin" version "1.0.0" apply false
21 | }
22 | }
23 |
24 | plugins {
25 | id "dev.flutter.flutter-plugin-loader" version "1.0.0"
26 | id "com.android.application" version "7.3.0" apply false
27 | }
28 |
29 | include ":app"
30 |
--------------------------------------------------------------------------------
/bricks/feature_riverpod_architecture/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # 0.1.0+1
2 |
3 | - TODO: Describe initial release.
4 |
--------------------------------------------------------------------------------
/bricks/feature_riverpod_architecture/LICENSE:
--------------------------------------------------------------------------------
1 | TODO: Add your license here.
2 |
--------------------------------------------------------------------------------
/bricks/feature_riverpod_architecture/README.md:
--------------------------------------------------------------------------------
1 | # feature_package
2 |
3 | [](https://github.com/felangel/mason)
4 |
5 | A
6 |
7 | _Generated by [mason][1] 🧱_
8 |
9 | ## Getting Started 🚀
10 |
11 | This is a starting point for a new brick.
12 | A few resources to get you started if this is your first brick template:
13 |
14 | - [Official Mason Documentation][2]
15 | - [Code generation with Mason Blog][3]
16 | - [Very Good Livestream: Felix Angelov Demos Mason][4]
17 | - [Flutter Package of the Week: Mason][5]
18 | - [Observable Flutter: Building a Mason brick][6]
19 | - [Meet Mason: Flutter Vikings 2022][7]
20 |
21 | [1]: https://github.com/felangel/mason
22 | [2]: https://docs.brickhub.dev
23 | [3]: https://verygood.ventures/blog/code-generation-with-mason
24 | [4]: https://youtu.be/G4PTjA6tpTU
25 | [5]: https://youtu.be/qjA0JFiPMnQ
26 | [6]: https://youtu.be/o8B1EfcUisw
27 | [7]: https://youtu.be/LXhgiF5HiQg
28 |
--------------------------------------------------------------------------------
/bricks/feature_riverpod_architecture/__brick__/{{feature_name.snakeCase()}}/application/application.dart:
--------------------------------------------------------------------------------
1 | class WeatherService {}
2 |
--------------------------------------------------------------------------------
/bricks/feature_riverpod_architecture/__brick__/{{feature_name.snakeCase()}}/data/data_source/weather_api.dart:
--------------------------------------------------------------------------------
1 | /// Uri builder class for the OpenWeatherMap API
2 | ///
3 | /// https://github.com/bizz84/open_weather_example_flutter/blob/main/lib/src/api/api.dart
4 | class OpenWeatherMapAPI {
5 | OpenWeatherMapAPI(this.apiKey);
6 | final String apiKey;
7 |
8 | static const String _apiBaseUrl = 'api.openweathermap.org';
9 | static const String _apiPath = '/data/2.5/';
10 |
11 | Uri weather(String city) => _buildUri(
12 | endpoint: 'weather',
13 | parametersBuilder: () => cityQueryParameters(city),
14 | );
15 |
16 | Uri forecast(String city) => _buildUri(
17 | endpoint: 'forecast',
18 | parametersBuilder: () => cityQueryParameters(city),
19 | );
20 |
21 | Uri _buildUri({
22 | required String endpoint,
23 | required Map Function() parametersBuilder,
24 | }) {
25 | return Uri(
26 | scheme: 'https',
27 | host: _apiBaseUrl,
28 | path: '$_apiPath$endpoint',
29 | queryParameters: parametersBuilder(),
30 | );
31 | }
32 |
33 | Map cityQueryParameters(String city) => {
34 | 'q': city,
35 | 'appid': apiKey,
36 | 'units': 'metric',
37 | };
38 | }
39 |
--------------------------------------------------------------------------------
/bricks/feature_riverpod_architecture/__brick__/{{feature_name.snakeCase()}}/data/repository/repository_providers.dart:
--------------------------------------------------------------------------------
1 | import 'package:http/http.dart' as http;
2 | import 'package:riverpod_annotation/riverpod_annotation.dart';
3 |
4 | import '../data_source/weather_api.dart';
5 | import 'weather_repository.dart';
6 |
7 | part 'repository_providers.g.dart';
8 |
9 | @riverpod
10 | HttpWeatherRepository weatherRepository(WeatherRepositoryRef ref) {
11 | return HttpWeatherRepository(
12 | api: OpenWeatherMapAPI(''),
13 | client: http.Client(),
14 | );
15 | }
16 |
--------------------------------------------------------------------------------
/bricks/feature_riverpod_architecture/__brick__/{{feature_name.snakeCase()}}/data/repository/repository_providers.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'repository_providers.dart';
4 |
5 | // **************************************************************************
6 | // RiverpodGenerator
7 | // **************************************************************************
8 |
9 | String _$weatherRepositoryHash() => r'8ae397422adc069b5cc48dfafc03e9697d4087a4';
10 |
11 | /// See also [weatherRepository].
12 | @ProviderFor(weatherRepository)
13 | final weatherRepositoryProvider =
14 | AutoDisposeProvider.internal(
15 | weatherRepository,
16 | name: r'weatherRepositoryProvider',
17 | debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
18 | ? null
19 | : _$weatherRepositoryHash,
20 | dependencies: null,
21 | allTransitiveDependencies: null,
22 | );
23 |
24 | typedef WeatherRepositoryRef = AutoDisposeProviderRef;
25 | // ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions
26 |
--------------------------------------------------------------------------------
/bricks/feature_riverpod_architecture/__brick__/{{feature_name.snakeCase()}}/data/repository/weather_repository.dart:
--------------------------------------------------------------------------------
1 | import 'package:http/http.dart' as http;
2 |
3 | import '../data_source/weather_api.dart';
4 | import '../dto/weather.dart';
5 |
6 | class HttpWeatherRepository implements WeatherRepository {
7 | HttpWeatherRepository({required this.api, required this.client});
8 | // custom class defining all the API details
9 | final OpenWeatherMapAPI api;
10 | // client for making calls to the API
11 | final http.Client client;
12 |
13 | @override
14 | Future getWeather({required String city}) async {
15 | final result = await client.get(api.weather(city));
16 | return Weather.fromJson(result.body);
17 | }
18 | }
19 |
20 | abstract class WeatherRepository {
21 | Future getWeather({required String city});
22 | }
23 |
--------------------------------------------------------------------------------
/bricks/feature_riverpod_architecture/__brick__/{{feature_name.snakeCase()}}/domain/entity/user_account.dart:
--------------------------------------------------------------------------------
1 | import 'package:freezed_annotation/freezed_annotation.dart';
2 | import 'package:modddels_annotation_fpdart/modddels_annotation_fpdart.dart';
3 |
4 | import '../value/email.dart';
5 | import '../value/id.dart';
6 | import '../value/name.dart';
7 |
8 | part 'user_account.freezed.dart';
9 | part 'user_account.modddel.dart';
10 |
11 | @Modddel(
12 | validationSteps: [
13 | ValidationStep([
14 | contentValidation,
15 | ]),
16 | ValidationStep([
17 | Validation('account', FailureType()),
18 | ], name: 'Value')
19 | ],
20 | )
21 | class UserAccount extends SimpleEntity
22 | with _$UserAccount {
23 | UserAccount._();
24 |
25 | factory UserAccount({
26 | required Id id,
27 | required Name name,
28 | required Email email,
29 | }) {
30 | return _$UserAccount._create(id: id, name: name, email: email);
31 | }
32 |
33 | @override
34 | Option validateAccount(userAccount) {
35 | return none();
36 | }
37 | }
38 |
39 | @freezed
40 | class UserAccountValidFailure extends EntityFailure
41 | with _$UserAccountValidFailure {
42 | const factory UserAccountValidFailure.invalid() = _Invalid;
43 | }
44 |
45 | final UserAccount user = UserAccount(
46 | id: Id('id'),
47 | name: Name(firstName: 'firstName', lastName: 'lastName'),
48 | email: Email('email'),
49 | );
50 |
--------------------------------------------------------------------------------
/bricks/feature_riverpod_architecture/__brick__/{{feature_name.snakeCase()}}/domain/value/email.dart:
--------------------------------------------------------------------------------
1 | import 'package:freezed_annotation/freezed_annotation.dart';
2 | import 'package:modddels_annotation_fpdart/modddels_annotation_fpdart.dart';
3 |
4 | part 'email.freezed.dart';
5 | part 'email.modddel.dart';
6 |
7 | @Modddel(validationSteps: [
8 | ValidationStep([
9 | Validation('format', FailureType()),
10 | Validation('available', FailureType()),
11 | ], name: 'Value'),
12 | ])
13 | class Email extends SingleValueObject with _$Email {
14 | const Email._();
15 |
16 | factory Email(String value) => _$Email._create(value: value);
17 |
18 | @override
19 | Option validateFormat(email) {
20 | if (email.value.isEmpty) {
21 | // also check for valid email format
22 | return some(const EmailFormatFailure.invalid());
23 | }
24 | return none();
25 | }
26 |
27 | @override
28 | Option validateAvailable(email) {
29 | if (email.value == 'example_taken@gmail.com') {
30 | return some(const EmailAvailableFailure.taken());
31 | }
32 | return none();
33 | }
34 | }
35 |
36 | @freezed
37 | class EmailAvailableFailure extends ValueFailure with _$EmailAvailableFailure {
38 | const factory EmailAvailableFailure.taken() = _Taken;
39 | const factory EmailAvailableFailure.reserved() = _Reserved;
40 | const factory EmailAvailableFailure.banned() = _Banned;
41 | }
42 |
43 | @freezed
44 | class EmailFormatFailure extends ValueFailure with _$EmailFormatFailure {
45 | const factory EmailFormatFailure.invalid() = _Invalid;
46 | }
47 |
--------------------------------------------------------------------------------
/bricks/feature_riverpod_architecture/__brick__/{{feature_name.snakeCase()}}/domain/value/id.dart:
--------------------------------------------------------------------------------
1 | import 'package:freezed_annotation/freezed_annotation.dart';
2 | import 'package:modddels_annotation_fpdart/modddels_annotation_fpdart.dart';
3 |
4 | part 'id.freezed.dart';
5 | part 'id.modddel.dart';
6 |
7 | @Modddel(validationSteps: [
8 | ValidationStep([
9 | Validation('allowed', FailureType()),
10 | ], name: 'Value')
11 | ])
12 | class Id extends SingleValueObject with _$Id {
13 | const Id._();
14 |
15 | factory Id(
16 | String value,
17 | ) =>
18 | _$Id._create(value: value);
19 |
20 | @override
21 | Option validateAllowed(id) {
22 | if (id.value.isEmpty) {
23 | // also check for valid email format
24 | return some(const IdValidFailure.invalid());
25 | }
26 |
27 | return none();
28 | }
29 | }
30 |
31 | @freezed
32 | class IdValidFailure extends ValueFailure with _$IdValidFailure {
33 | const factory IdValidFailure.invalid() = _Invalid;
34 | }
35 |
--------------------------------------------------------------------------------
/bricks/feature_riverpod_architecture/__brick__/{{feature_name.snakeCase()}}/domain/value/name.dart:
--------------------------------------------------------------------------------
1 | import 'package:freezed_annotation/freezed_annotation.dart';
2 | import 'package:modddels_annotation_fpdart/modddels_annotation_fpdart.dart';
3 |
4 | part 'name.freezed.dart';
5 | part 'name.modddel.dart';
6 |
7 | @Modddel(validationSteps: [
8 | ValidationStep([
9 | Validation('allowed', FailureType()),
10 | ], name: 'Value')
11 | ])
12 | class Name extends MultiValueObject with _$Name {
13 | const Name._();
14 |
15 | factory Name({
16 | required String firstName,
17 | required String lastName,
18 | String middleName = '',
19 | }) =>
20 | _$Name._create(
21 | firstName: firstName, lastName: lastName, middleName: middleName);
22 |
23 | @override
24 | Option validateAllowed(name) {
25 | if (name.firstName.isEmpty || name.lastName.isEmpty) {
26 | // also check for valid email format
27 | return some(const NameValidFailure.empty());
28 | }
29 |
30 | return none();
31 | }
32 | }
33 |
34 | @freezed
35 | class NameValidFailure extends ValueFailure with _$NameValidFailure {
36 | const factory NameValidFailure.illegalCharacters() = _IllegalCharacters;
37 | const factory NameValidFailure.obscene() = _Obscene;
38 | const factory NameValidFailure.empty() = _Empty;
39 | }
40 |
--------------------------------------------------------------------------------
/bricks/feature_riverpod_architecture/__brick__/{{feature_name.snakeCase()}}/presentation/feature_first_widget.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/widgets.dart';
2 |
3 | class FeatureFirst extends StatelessWidget {
4 | const FeatureFirst({super.key});
5 |
6 | @override
7 | Widget build(BuildContext context) {
8 | return const Placeholder();
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/bricks/feature_riverpod_architecture/brick.yaml:
--------------------------------------------------------------------------------
1 | name: feature_riverpod_architecture
2 | description: A new Flutter feature package with Riverpod Architecture.
3 |
4 | # The following defines the brick repository url.
5 | # Uncomment and update the following line before publishing the brick.
6 | # repository: https://github.com/my_org/my_repo
7 |
8 | # The following defines the version and build number for your brick.
9 | # A version number is three numbers separated by dots, like 1.2.34
10 | # followed by an optional build number (separated by a +).
11 | version: 0.1.0+1
12 |
13 | # The following defines the environment for the current brick.
14 | # It includes the version of mason that the brick requires.
15 | environment:
16 | mason: ">=0.1.0-dev.49 <0.1.0"
17 |
18 | # Variables specify dynamic values that your brick depends on.
19 | # Zero or more variables can be specified for a given brick.
20 | # Each variable has:
21 | # * a type (string, number, boolean, enum, or array)
22 | # * an optional short description
23 | # * an optional default value
24 | # * an optional list of default values (array only)
25 | # * an optional prompt phrase used when asking for the variable
26 | # * a list of values (enums only)
27 | vars:
28 | feature_name:
29 | type: string
30 | description: Feature name
31 | default: Dash
32 | prompt: What is the feature name?
33 |
--------------------------------------------------------------------------------
/codecov.yml:
--------------------------------------------------------------------------------
1 | ignore:
2 | - "**/example/"
3 | - "**/*.g.dart"
4 | - "**/*.gen.dart"
5 | - "lib/generated_plugin_registrant.dart"
6 | - "**/*.freezed.dart"
7 | - "**/*.mapper.dart"
8 | # This is generated from the i18n vscode extension
9 | - "**/*.i18n.dart"
10 | - "lib/generated/intl/messages*.dart"
11 | - "packages/*"
12 |
--------------------------------------------------------------------------------
/codemagic.yaml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getBoolean/flutter_boolean_template/5ebb31262d732441601fba7785ae863ca34a24d0/codemagic.yaml
--------------------------------------------------------------------------------
/dart_test.yaml:
--------------------------------------------------------------------------------
1 | tags:
2 | presubmit-only:
3 | skip: "Should only be run during presubmit"
4 |
--------------------------------------------------------------------------------
/devtools_options.yaml:
--------------------------------------------------------------------------------
1 | extensions:
2 |
--------------------------------------------------------------------------------
/docs/creating_bricks.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getBoolean/flutter_boolean_template/5ebb31262d732441601fba7785ae863ca34a24d0/docs/creating_bricks.png
--------------------------------------------------------------------------------
/docs/example_layers.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getBoolean/flutter_boolean_template/5ebb31262d732441601fba7785ae863ca34a24d0/docs/example_layers.webp
--------------------------------------------------------------------------------
/integration_test/example_test.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_boolean_template/app.dart';
3 | import 'package:flutter_test/flutter_test.dart';
4 | import 'package:hooks_riverpod/hooks_riverpod.dart';
5 | import 'package:patrol/patrol.dart';
6 |
7 | void main() {
8 | patrolTest(
9 | 'counter state is the same after going to home and going back',
10 | skip: true,
11 | ($) async {
12 | await $.pumpWidgetAndSettle(const ProviderScope(child: App()));
13 |
14 | await $(FloatingActionButton).tap();
15 | expect($(#counterText).text, '1');
16 |
17 | await $.native.pressHome();
18 | await $.native.pressDoubleRecentApps();
19 |
20 | expect($(#counterText).text, '1');
21 | await $(FloatingActionButton).tap();
22 | expect($(#counterText).text, '2');
23 |
24 | await $.native.openNotifications();
25 | await $.native.pressBack();
26 | },
27 | );
28 | }
29 |
--------------------------------------------------------------------------------
/ios/.gitignore:
--------------------------------------------------------------------------------
1 | **/dgph
2 | *.mode1v3
3 | *.mode2v3
4 | *.moved-aside
5 | *.pbxuser
6 | *.perspectivev3
7 | **/*sync/
8 | .sconsign.dblite
9 | .tags*
10 | **/.vagrant/
11 | **/DerivedData/
12 | Icon?
13 | **/Pods/
14 | **/.symlinks/
15 | profile
16 | xcuserdata
17 | **/.generated/
18 | Flutter/App.framework
19 | Flutter/Flutter.framework
20 | Flutter/Flutter.podspec
21 | Flutter/Generated.xcconfig
22 | Flutter/ephemeral/
23 | Flutter/app.flx
24 | Flutter/app.zip
25 | Flutter/flutter_assets/
26 | Flutter/flutter_export_environment.sh
27 | ServiceDefinitions.json
28 | Runner/GeneratedPluginRegistrant.*
29 |
30 | # Exceptions to above rules.
31 | !default.mode1v3
32 | !default.mode2v3
33 | !default.pbxuser
34 | !default.perspectivev3
35 |
--------------------------------------------------------------------------------
/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 12.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getBoolean/flutter_boolean_template/5ebb31262d732441601fba7785ae863ca34a24d0/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getBoolean/flutter_boolean_template/5ebb31262d732441601fba7785ae863ca34a24d0/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getBoolean/flutter_boolean_template/5ebb31262d732441601fba7785ae863ca34a24d0/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getBoolean/flutter_boolean_template/5ebb31262d732441601fba7785ae863ca34a24d0/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getBoolean/flutter_boolean_template/5ebb31262d732441601fba7785ae863ca34a24d0/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getBoolean/flutter_boolean_template/5ebb31262d732441601fba7785ae863ca34a24d0/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getBoolean/flutter_boolean_template/5ebb31262d732441601fba7785ae863ca34a24d0/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getBoolean/flutter_boolean_template/5ebb31262d732441601fba7785ae863ca34a24d0/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getBoolean/flutter_boolean_template/5ebb31262d732441601fba7785ae863ca34a24d0/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getBoolean/flutter_boolean_template/5ebb31262d732441601fba7785ae863ca34a24d0/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getBoolean/flutter_boolean_template/5ebb31262d732441601fba7785ae863ca34a24d0/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getBoolean/flutter_boolean_template/5ebb31262d732441601fba7785ae863ca34a24d0/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getBoolean/flutter_boolean_template/5ebb31262d732441601fba7785ae863ca34a24d0/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getBoolean/flutter_boolean_template/5ebb31262d732441601fba7785ae863ca34a24d0/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getBoolean/flutter_boolean_template/5ebb31262d732441601fba7785ae863ca34a24d0/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getBoolean/flutter_boolean_template/5ebb31262d732441601fba7785ae863ca34a24d0/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getBoolean/flutter_boolean_template/5ebb31262d732441601fba7785ae863ca34a24d0/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getBoolean/flutter_boolean_template/5ebb31262d732441601fba7785ae863ca34a24d0/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/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.
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
2 |
--------------------------------------------------------------------------------
/lib/src/common/exceptions/app_exeption.dart:
--------------------------------------------------------------------------------
1 | class AppException implements Exception {
2 | final String? message;
3 | final String? prefix;
4 |
5 | AppException([this.message, this.prefix]);
6 |
7 | @override
8 | String toString() {
9 | return '$prefix$message';
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/lib/src/common/widgets/animated_fade_switcher.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class AnimatedFadeSwitcher extends StatelessWidget {
4 | const AnimatedFadeSwitcher({
5 | required this.shouldSwitch,
6 | required this.child,
7 | required this.secondChild,
8 | super.key,
9 | });
10 |
11 | final bool shouldSwitch;
12 | final Widget child;
13 | final Widget secondChild;
14 |
15 | @override
16 | Widget build(BuildContext context) {
17 | return AnimatedSwitcher(
18 | duration: const Duration(milliseconds: 150),
19 | transitionBuilder: (Widget child, Animation animation) {
20 | return FadeTransition(
21 | opacity: animation,
22 | child: child,
23 | );
24 | },
25 | child: shouldSwitch ? child : secondChild,
26 | );
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/lib/src/common/widgets/blank.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class Blank extends StatelessWidget {
4 | const Blank({super.key});
5 |
6 | @override
7 | Widget build(BuildContext context) {
8 | return const Placeholder();
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/lib/src/common/widgets/prototype_height.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | /// https://stackoverflow.com/a/73189727
4 | class PrototypeHeight extends StatelessWidget {
5 | final Widget prototype;
6 | final ListView listView;
7 |
8 | const PrototypeHeight({
9 | required this.prototype,
10 | required this.listView,
11 | super.key,
12 | });
13 |
14 | @override
15 | Widget build(BuildContext context) {
16 | return Stack(
17 | children: [
18 | IgnorePointer(
19 | child: Opacity(
20 | opacity: 0.0,
21 | child: prototype,
22 | ),
23 | ),
24 | const SizedBox(width: double.infinity),
25 | PositionedDirectional(child: listView),
26 | ],
27 | );
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/lib/src/features/books/presentation/book_details_screen.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class BookDetailsScreen extends StatelessWidget {
4 | const BookDetailsScreen({
5 | this.id,
6 | super.key,
7 | });
8 | final String? id;
9 |
10 | @override
11 | Widget build(BuildContext context) {
12 | return ColoredBox(
13 | color: Colors.blueAccent,
14 | child: Center(
15 | child: Text(
16 | id != null ? 'Book $id' : 'Book Details Screen',
17 | ),
18 | ),
19 | );
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/lib/src/features/books/presentation/books_screen.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_boolean_template/src/features/connectivity/presentation/offline_warning_widget.dart';
3 | import 'package:flutter_boolean_template/src/routing/router/router.dart';
4 | import 'package:go_router/go_router.dart';
5 |
6 | class BooksScreen extends StatelessWidget {
7 | const BooksScreen({
8 | super.key,
9 | });
10 |
11 | @override
12 | Widget build(BuildContext context) {
13 | return Scaffold(
14 | floatingActionButton: FloatingActionButton(
15 | onPressed: () {},
16 | tooltip: 'Add a new book',
17 | child: const Icon(Icons.add),
18 | ),
19 | body: Column(
20 | crossAxisAlignment: CrossAxisAlignment.stretch,
21 | children: [
22 | const OfflineWarningBanner(),
23 | Expanded(
24 | child: ColoredBox(
25 | color: Colors.blue,
26 | child: Center(
27 | child: FilledButton(
28 | key: const ValueKey('button'),
29 | onPressed: () async {
30 | const String id = '1';
31 | context.goNamed(
32 | RouteName.bookDetails.name,
33 | pathParameters: {'id': id},
34 | );
35 | },
36 | child: const Text('Push Details'),
37 | ),
38 | ),
39 | ),
40 | ),
41 | ],
42 | ),
43 | );
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/lib/src/features/connectivity/presentation/offline_warning_widget.dart:
--------------------------------------------------------------------------------
1 | import 'package:connectivity_plus/connectivity_plus.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_boolean_template/src/features/connectivity/presentation/connectivity_builder.dart';
4 | import 'package:hooks_riverpod/hooks_riverpod.dart';
5 |
6 | class OfflineWarningBanner extends ConsumerWidget {
7 | const OfflineWarningBanner({super.key});
8 |
9 | @override
10 | Widget build(BuildContext context, WidgetRef ref) {
11 | final theme = Theme.of(context);
12 |
13 | return ConnectivityBuilder(
14 | builder: (context, connectivity, child) =>
15 | connectivity.contains(ConnectivityResult.none)
16 | ? child ?? const SizedBox.shrink()
17 | : const SizedBox.shrink(),
18 | child: ColoredBox(
19 | color: theme.colorScheme.onError,
20 | child: Padding(
21 | padding: const EdgeInsetsDirectional.all(8),
22 | child: Center(
23 | child: Text(
24 | 'No internet connection',
25 | style: TextStyle(color: theme.colorScheme.error),
26 | ),
27 | ),
28 | ),
29 | ),
30 | );
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/lib/src/features/example_feature/application/application.dart:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/lib/src/features/example_feature/data/data_source/weather_api.dart:
--------------------------------------------------------------------------------
1 | /// Uri builder class for the OpenWeatherMap API
2 | ///
3 | /// https://github.com/bizz84/open_weather_example_flutter/blob/main/lib/src/api/api.dart
4 | class OpenWeatherMapAPI {
5 | OpenWeatherMapAPI(this.apiKey);
6 | final String apiKey;
7 |
8 | static const String _apiBaseUrl = 'api.openweathermap.org';
9 | static const String _apiPath = '/data/2.5/';
10 |
11 | Uri weather(String city) => _buildUri(
12 | endpoint: 'weather',
13 | parametersBuilder: () => cityQueryParameters(city),
14 | );
15 |
16 | Uri forecast(String city) => _buildUri(
17 | endpoint: 'forecast',
18 | parametersBuilder: () => cityQueryParameters(city),
19 | );
20 |
21 | Uri _buildUri({
22 | required String endpoint,
23 | required Map Function() parametersBuilder,
24 | }) {
25 | return Uri(
26 | scheme: 'https',
27 | host: _apiBaseUrl,
28 | path: '$_apiPath$endpoint',
29 | queryParameters: parametersBuilder(),
30 | );
31 | }
32 |
33 | Map cityQueryParameters(String city) => {
34 | 'q': city,
35 | 'appid': apiKey,
36 | 'units': 'metric',
37 | };
38 | }
39 |
--------------------------------------------------------------------------------
/lib/src/features/example_feature/data/repository/repository_providers.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_boolean_template/src/features/example_feature/data/data_source/weather_api.dart';
2 | import 'package:flutter_boolean_template/src/features/example_feature/data/repository/weather_repository.dart';
3 | import 'package:http/http.dart' as http;
4 | import 'package:riverpod_annotation/riverpod_annotation.dart';
5 |
6 | part 'repository_providers.g.dart';
7 |
8 | @riverpod
9 | HttpWeatherRepository weatherRepository(WeatherRepositoryRef ref) {
10 | return HttpWeatherRepository(
11 | api: OpenWeatherMapAPI(''),
12 | client: http.Client(),
13 | );
14 | }
15 |
--------------------------------------------------------------------------------
/lib/src/features/example_feature/data/repository/repository_providers.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'repository_providers.dart';
4 |
5 | // **************************************************************************
6 | // RiverpodGenerator
7 | // **************************************************************************
8 |
9 | String _$weatherRepositoryHash() => r'8ae397422adc069b5cc48dfafc03e9697d4087a4';
10 |
11 | /// See also [weatherRepository].
12 | @ProviderFor(weatherRepository)
13 | final weatherRepositoryProvider =
14 | AutoDisposeProvider.internal(
15 | weatherRepository,
16 | name: r'weatherRepositoryProvider',
17 | debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
18 | ? null
19 | : _$weatherRepositoryHash,
20 | dependencies: null,
21 | allTransitiveDependencies: null,
22 | );
23 |
24 | typedef WeatherRepositoryRef = AutoDisposeProviderRef;
25 | // ignore_for_file: type=lint
26 | // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
27 |
--------------------------------------------------------------------------------
/lib/src/features/example_feature/data/repository/weather_repository.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_boolean_template/src/features/example_feature/data/data_source/weather_api.dart';
2 | import 'package:flutter_boolean_template/src/features/example_feature/data/dto/weather.dart';
3 | import 'package:http/http.dart' as http;
4 |
5 | abstract class WeatherRepository {
6 | Future getWeather({required String city});
7 | }
8 |
9 | class HttpWeatherRepository implements WeatherRepository {
10 | /// custom class defining all the API details
11 | final OpenWeatherMapAPI api;
12 |
13 | /// client for making calls to the API
14 | final http.Client client;
15 |
16 | HttpWeatherRepository({required this.api, required this.client});
17 |
18 | @override
19 | Future getWeather({required String city}) async {
20 | final result = await client.get(api.weather(city));
21 |
22 | return Weather.fromJson(result.body);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/lib/src/features/example_feature/domain/entity/user_account.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_boolean_template/src/features/example_feature/domain/value/email.dart';
2 | import 'package:flutter_boolean_template/src/features/example_feature/domain/value/id.dart';
3 | import 'package:flutter_boolean_template/src/features/example_feature/domain/value/name.dart';
4 | import 'package:freezed_annotation/freezed_annotation.dart';
5 | import 'package:modddels_annotation_fpdart/modddels_annotation_fpdart.dart';
6 |
7 | part 'user_account.freezed.dart';
8 | part 'user_account.modddel.dart';
9 |
10 | @Modddel(
11 | validationSteps: [
12 | ValidationStep([
13 | contentValidation,
14 | ]),
15 | ValidationStep(
16 | [
17 | Validation('account', FailureType()),
18 | ],
19 | name: 'Value',
20 | ),
21 | ],
22 | )
23 | class UserAccount extends SimpleEntity
24 | with _$UserAccount {
25 | factory UserAccount({
26 | required Id id,
27 | required Name name,
28 | required Email email,
29 | }) {
30 | return _$UserAccount._create(id: id, name: name, email: email);
31 | }
32 | UserAccount._();
33 |
34 | @override
35 | Option validateAccount(
36 | _ValidateUserAccountAccount userAccount,
37 | ) {
38 | return none();
39 | }
40 | }
41 |
42 | @freezed
43 | class UserAccountValidFailure extends EntityFailure
44 | with _$UserAccountValidFailure {
45 | const factory UserAccountValidFailure.invalid() = _Invalid;
46 | }
47 |
48 | final UserAccount user = UserAccount(
49 | id: Id('id'),
50 | name: Name(firstName: 'firstName', lastName: 'lastName'),
51 | email: Email('email'),
52 | );
53 |
--------------------------------------------------------------------------------
/lib/src/features/example_feature/domain/value/id.dart:
--------------------------------------------------------------------------------
1 | import 'package:freezed_annotation/freezed_annotation.dart';
2 | import 'package:modddels_annotation_fpdart/modddels_annotation_fpdart.dart';
3 |
4 | part 'id.freezed.dart';
5 | part 'id.modddel.dart';
6 |
7 | @Modddel(
8 | validationSteps: [
9 | ValidationStep(
10 | [
11 | Validation('allowed', FailureType()),
12 | ],
13 | name: 'Value',
14 | ),
15 | ],
16 | )
17 | class Id extends SingleValueObject with _$Id {
18 | factory Id(
19 | String value,
20 | ) =>
21 | _$Id._create(value: value);
22 | const Id._();
23 |
24 | @override
25 | Option validateAllowed(_ValidateIdAllowed id) {
26 | if (id.value.isEmpty) {
27 | // also check for valid email format
28 | return some(const IdValidFailure.invalid());
29 | }
30 |
31 | return none();
32 | }
33 | }
34 |
35 | @freezed
36 | class IdValidFailure extends ValueFailure with _$IdValidFailure {
37 | const factory IdValidFailure.invalid() = _Invalid;
38 | }
39 |
--------------------------------------------------------------------------------
/lib/src/features/example_feature/domain/value/name.dart:
--------------------------------------------------------------------------------
1 | import 'package:freezed_annotation/freezed_annotation.dart';
2 | import 'package:modddels_annotation_fpdart/modddels_annotation_fpdart.dart';
3 |
4 | part 'name.freezed.dart';
5 | part 'name.modddel.dart';
6 |
7 | @Modddel(
8 | validationSteps: [
9 | ValidationStep(
10 | [
11 | Validation('allowed', FailureType()),
12 | ],
13 | name: 'Value',
14 | ),
15 | ],
16 | )
17 | class Name extends MultiValueObject with _$Name {
18 | factory Name({
19 | required String firstName,
20 | required String lastName,
21 | String middleName = '',
22 | }) =>
23 | _$Name._create(
24 | firstName: firstName,
25 | lastName: lastName,
26 | middleName: middleName,
27 | );
28 | const Name._();
29 |
30 | @override
31 | Option validateAllowed(_ValidateNameAllowed name) {
32 | if (name.firstName.isEmpty || name.lastName.isEmpty) {
33 | // also check for valid email format
34 | return some(const NameValidFailure.empty());
35 | }
36 |
37 | return none();
38 | }
39 | }
40 |
41 | @freezed
42 | class NameValidFailure extends ValueFailure with _$NameValidFailure {
43 | const factory NameValidFailure.illegalCharacters() = _IllegalCharacters;
44 | const factory NameValidFailure.obscene() = _Obscene;
45 | const factory NameValidFailure.empty() = _Empty;
46 | }
47 |
--------------------------------------------------------------------------------
/lib/src/features/example_feature/presentation/feature_first_widget.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/widgets.dart';
2 |
3 | class FeatureFirst extends StatelessWidget {
4 | const FeatureFirst({super.key});
5 |
6 | @override
7 | Widget build(BuildContext context) {
8 | return const Placeholder();
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/lib/src/features/initialization/application/app_startup.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'app_startup.dart';
4 |
5 | // **************************************************************************
6 | // RiverpodGenerator
7 | // **************************************************************************
8 |
9 | String _$appStartupHash() => r'bbff25e518f1360b1ec738b582843e0648da9bc6';
10 |
11 | /// See also [appStartup].
12 | @ProviderFor(appStartup)
13 | final appStartupProvider = FutureProvider.internal(
14 | appStartup,
15 | name: r'appStartupProvider',
16 | debugGetCreateSourceHash:
17 | const bool.fromEnvironment('dart.vm.product') ? null : _$appStartupHash,
18 | dependencies: null,
19 | allTransitiveDependencies: null,
20 | );
21 |
22 | typedef AppStartupRef = FutureProviderRef;
23 | // ignore_for_file: type=lint
24 | // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
25 |
--------------------------------------------------------------------------------
/lib/src/features/initialization/application/info_service.dart:
--------------------------------------------------------------------------------
1 | import 'package:package_info_plus/package_info_plus.dart';
2 | import 'package:riverpod_annotation/riverpod_annotation.dart';
3 |
4 | part 'info_service.g.dart';
5 |
6 | @Riverpod(keepAlive: true)
7 | Future packageInfo(PackageInfoRef ref) async {
8 | return await PackageInfo.fromPlatform();
9 | }
10 |
--------------------------------------------------------------------------------
/lib/src/features/initialization/application/info_service.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'info_service.dart';
4 |
5 | // **************************************************************************
6 | // RiverpodGenerator
7 | // **************************************************************************
8 |
9 | String _$packageInfoHash() => r'9fe479523e8271f8a97e79dcdc75029c05d9c483';
10 |
11 | /// See also [packageInfo].
12 | @ProviderFor(packageInfo)
13 | final packageInfoProvider = FutureProvider.internal(
14 | packageInfo,
15 | name: r'packageInfoProvider',
16 | debugGetCreateSourceHash:
17 | const bool.fromEnvironment('dart.vm.product') ? null : _$packageInfoHash,
18 | dependencies: null,
19 | allTransitiveDependencies: null,
20 | );
21 |
22 | typedef PackageInfoRef = FutureProviderRef;
23 | // ignore_for_file: type=lint
24 | // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
25 |
--------------------------------------------------------------------------------
/lib/src/features/profile/presentation/profile_details_screen.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class ProfileDetailsScreen extends StatelessWidget {
4 | const ProfileDetailsScreen({
5 | super.key,
6 | });
7 |
8 | @override
9 | Widget build(BuildContext context) {
10 | return const ColoredBox(
11 | color: Colors.deepPurpleAccent,
12 | child: Center(child: Text('Profile Details Screen')),
13 | );
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/lib/src/features/profile/presentation/profile_screen.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_boolean_template/src/routing/router/router.dart';
3 | import 'package:go_router/go_router.dart';
4 |
5 | class ProfileScreen extends StatelessWidget {
6 | const ProfileScreen({
7 | super.key,
8 | });
9 |
10 | @override
11 | Widget build(BuildContext context) {
12 | return Scaffold(
13 | body: ColoredBox(
14 | color: Colors.deepPurple,
15 | child: Center(
16 | child: FilledButton(
17 | onPressed: () {
18 | context.goNamed(RouteName.profileDetails.name);
19 | },
20 | child: const Text('Push Details'),
21 | ),
22 | ),
23 | ),
24 | );
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/lib/src/features/settings/application/settings_service.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'settings_service.dart';
4 |
5 | // **************************************************************************
6 | // RiverpodGenerator
7 | // **************************************************************************
8 |
9 | String _$settingsServiceHash() => r'6d000e6d764c3affb2d23d0bb786826d8781d18f';
10 |
11 | /// See also [SettingsService].
12 | @ProviderFor(SettingsService)
13 | final settingsServiceProvider =
14 | AutoDisposeNotifierProvider.internal(
15 | SettingsService.new,
16 | name: r'settingsServiceProvider',
17 | debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
18 | ? null
19 | : _$settingsServiceHash,
20 | dependencies: null,
21 | allTransitiveDependencies: null,
22 | );
23 |
24 | typedef _$SettingsService = AutoDisposeNotifier;
25 | // ignore_for_file: type=lint
26 | // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
27 |
--------------------------------------------------------------------------------
/lib/src/features/settings/application/themes.dart:
--------------------------------------------------------------------------------
1 | import 'package:flex_color_scheme/flex_color_scheme.dart';
2 | import 'package:riverpod_annotation/riverpod_annotation.dart';
3 |
4 | part 'themes.g.dart';
5 |
6 | @riverpod
7 | List themes(ThemesRef ref) {
8 | return FlexColor.schemesList;
9 | }
10 |
--------------------------------------------------------------------------------
/lib/src/features/settings/application/themes.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'themes.dart';
4 |
5 | // **************************************************************************
6 | // RiverpodGenerator
7 | // **************************************************************************
8 |
9 | String _$themesHash() => r'20637844c0284f400e1e28876e82cc41c5b8c85b';
10 |
11 | /// See also [themes].
12 | @ProviderFor(themes)
13 | final themesProvider = AutoDisposeProvider>.internal(
14 | themes,
15 | name: r'themesProvider',
16 | debugGetCreateSourceHash:
17 | const bool.fromEnvironment('dart.vm.product') ? null : _$themesHash,
18 | dependencies: null,
19 | allTransitiveDependencies: null,
20 | );
21 |
22 | typedef ThemesRef = AutoDisposeProviderRef>;
23 | // ignore_for_file: type=lint
24 | // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
25 |
--------------------------------------------------------------------------------
/lib/src/features/settings/data/dto/human_name_enum.dart:
--------------------------------------------------------------------------------
1 | abstract class HumanReadableEnum {
2 | const HumanReadableEnum();
3 |
4 | String get humanName;
5 | }
6 |
--------------------------------------------------------------------------------
/lib/src/features/settings/data/dto/navigation_type_override.dart:
--------------------------------------------------------------------------------
1 | import 'package:dart_mappable/dart_mappable.dart';
2 | import 'package:flutter_boolean_template/src/features/settings/data/dto/human_name_enum.dart';
3 | import 'package:flutter_boolean_template/src/routing/data/navigation_type.dart';
4 | import 'package:hive_flutter/adapters.dart';
5 |
6 | part 'navigation_type_override.g.dart';
7 | part 'navigation_type_override.mapper.dart';
8 |
9 | @MappableEnum()
10 | @HiveType(typeId: 2)
11 | enum NavigationTypeOverride implements HumanReadableEnum {
12 | @HiveField(0)
13 | auto('Auto'),
14 | @HiveField(1)
15 | bottom('Bottom Bar'),
16 | @HiveField(3)
17 | drawer('Drawer'),
18 | @HiveField(4)
19 | sidebar('Sidebar'),
20 | @HiveField(5)
21 | top('Top Bar');
22 |
23 | const NavigationTypeOverride(this.humanName);
24 |
25 | @override
26 | final String humanName;
27 |
28 | bool get isAuto => this == NavigationTypeOverride.auto;
29 | }
30 |
31 | extension NavigationTypeOverrideConverter on NavigationTypeOverride {
32 | /// Converts the [NavigationTypeOverride] to a [NavigationType]
33 | ///
34 | /// [NavigationTypeOverride.auto] will be converted to [NavigationType.bottom]
35 | NavigationType get navigationType => switch (this) {
36 | NavigationTypeOverride.auto => NavigationType.bottom,
37 | NavigationTypeOverride.bottom => NavigationType.bottom,
38 | NavigationTypeOverride.drawer => NavigationType.drawer,
39 | NavigationTypeOverride.sidebar => NavigationType.sidebar,
40 | NavigationTypeOverride.top => NavigationType.top,
41 | };
42 | }
43 |
--------------------------------------------------------------------------------
/lib/src/features/settings/data/dto/theme_type.dart:
--------------------------------------------------------------------------------
1 | import 'package:dart_mappable/dart_mappable.dart';
2 | import 'package:flutter/material.dart' show ThemeMode;
3 | import 'package:flutter_boolean_template/src/features/settings/data/dto/human_name_enum.dart';
4 | import 'package:hive/hive.dart';
5 |
6 | part 'theme_type.g.dart';
7 | part 'theme_type.mapper.dart';
8 |
9 | @MappableEnum()
10 | @HiveType(typeId: 3)
11 | enum ThemeType implements HumanReadableEnum {
12 | @HiveField(0)
13 | light('Light'),
14 |
15 | @HiveField(1)
16 | dark('Dark'),
17 |
18 | @HiveField(2)
19 | system('System');
20 |
21 | const ThemeType(this.humanName);
22 |
23 | @override
24 | final String humanName;
25 |
26 | ThemeMode toThemeMode() {
27 | switch (this) {
28 | case ThemeType.light:
29 | return ThemeMode.light;
30 | case ThemeType.dark:
31 | return ThemeMode.dark;
32 | case ThemeType.system:
33 | return ThemeMode.system;
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/lib/src/features/settings/data/dto/theme_type.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'theme_type.dart';
4 |
5 | // **************************************************************************
6 | // TypeAdapterGenerator
7 | // **************************************************************************
8 |
9 | class ThemeTypeAdapter extends TypeAdapter {
10 | @override
11 | final int typeId = 3;
12 |
13 | @override
14 | ThemeType read(BinaryReader reader) {
15 | switch (reader.readByte()) {
16 | case 0:
17 | return ThemeType.light;
18 | case 1:
19 | return ThemeType.dark;
20 | case 2:
21 | return ThemeType.system;
22 | default:
23 | return ThemeType.light;
24 | }
25 | }
26 |
27 | @override
28 | void write(BinaryWriter writer, ThemeType obj) {
29 | switch (obj) {
30 | case ThemeType.light:
31 | writer.writeByte(0);
32 | break;
33 | case ThemeType.dark:
34 | writer.writeByte(1);
35 | break;
36 | case ThemeType.system:
37 | writer.writeByte(2);
38 | break;
39 | }
40 | }
41 |
42 | @override
43 | int get hashCode => typeId.hashCode;
44 |
45 | @override
46 | bool operator ==(Object other) =>
47 | identical(this, other) ||
48 | other is ThemeTypeAdapter &&
49 | runtimeType == other.runtimeType &&
50 | typeId == other.typeId;
51 | }
52 |
--------------------------------------------------------------------------------
/lib/src/features/settings/data/dto/theme_type.mapper.dart:
--------------------------------------------------------------------------------
1 | // coverage:ignore-file
2 | // GENERATED CODE - DO NOT MODIFY BY HAND
3 | // ignore_for_file: type=lint
4 | // ignore_for_file: unused_element, unnecessary_cast
5 | // ignore_for_file: strict_raw_type, inference_failure_on_untyped_parameter
6 |
7 | part of 'theme_type.dart';
8 |
9 | class ThemeTypeMapper extends EnumMapper {
10 | ThemeTypeMapper._();
11 |
12 | static ThemeTypeMapper? _instance;
13 | static ThemeTypeMapper ensureInitialized() {
14 | if (_instance == null) {
15 | MapperContainer.globals.use(_instance = ThemeTypeMapper._());
16 | }
17 | return _instance!;
18 | }
19 |
20 | static ThemeType fromValue(dynamic value) {
21 | ensureInitialized();
22 | return MapperContainer.globals.fromValue(value);
23 | }
24 |
25 | @override
26 | ThemeType decode(dynamic value) {
27 | switch (value) {
28 | case 'light':
29 | return ThemeType.light;
30 | case 'dark':
31 | return ThemeType.dark;
32 | case 'system':
33 | return ThemeType.system;
34 | default:
35 | throw MapperException.unknownEnumValue(value);
36 | }
37 | }
38 |
39 | @override
40 | dynamic encode(ThemeType self) {
41 | switch (self) {
42 | case ThemeType.light:
43 | return 'light';
44 | case ThemeType.dark:
45 | return 'dark';
46 | case ThemeType.system:
47 | return 'system';
48 | }
49 | }
50 | }
51 |
52 | extension ThemeTypeMapperExtension on ThemeType {
53 | String toValue() {
54 | ThemeTypeMapper.ensureInitialized();
55 | return MapperContainer.globals.toValue(this) as String;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/lib/src/features/settings/data/repository/settings_repository.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_boolean_template/src/features/settings/data/dto/settings.dart';
2 | import 'package:hive_flutter/hive_flutter.dart';
3 | import 'package:path/path.dart' as path;
4 | import 'package:riverpod_annotation/riverpod_annotation.dart';
5 |
6 | part 'settings_repository.g.dart';
7 |
8 | const String _settingsBoxName = 'settingsBox';
9 |
10 | @riverpod
11 | class SettingsRepository extends _$SettingsRepository {
12 | static Future initBox(String? directory) async =>
13 | await Hive.openBox(
14 | _settingsBoxName,
15 | path: directory == null
16 | ? null
17 | : path.join(directory, '.flutter_boolean_template'),
18 | );
19 | static Future deleteBox(String? directory) async =>
20 | await Hive.deleteBoxFromDisk(
21 | _settingsBoxName,
22 | path: directory == null
23 | ? null
24 | : path.join(directory, '.flutter_boolean_template'),
25 | );
26 |
27 | @override
28 | Settings build() {
29 | return getSettings();
30 | }
31 |
32 | void saveSettings(Settings settings) {
33 | Hive.box(_settingsBoxName).put('settings', settings);
34 | }
35 |
36 | Settings getSettings() {
37 | return Hive.box(_settingsBoxName).get('settings') ??
38 | const Settings();
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/lib/src/features/settings/data/repository/settings_repository.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'settings_repository.dart';
4 |
5 | // **************************************************************************
6 | // RiverpodGenerator
7 | // **************************************************************************
8 |
9 | String _$settingsRepositoryHash() =>
10 | r'06400a1c4c7e418bf57ec5bf6e6919be8a992d05';
11 |
12 | /// See also [SettingsRepository].
13 | @ProviderFor(SettingsRepository)
14 | final settingsRepositoryProvider =
15 | AutoDisposeNotifierProvider.internal(
16 | SettingsRepository.new,
17 | name: r'settingsRepositoryProvider',
18 | debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
19 | ? null
20 | : _$settingsRepositoryHash,
21 | dependencies: null,
22 | allTransitiveDependencies: null,
23 | );
24 |
25 | typedef _$SettingsRepository = AutoDisposeNotifier;
26 | // ignore_for_file: type=lint
27 | // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
28 |
--------------------------------------------------------------------------------
/lib/src/features/settings/presentation/extensions.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_boolean_template/src/features/settings/data/dto/human_name_enum.dart';
3 | import 'package:flutter_boolean_template/src/features/settings/data/dto/settings.dart';
4 | import 'package:flutter_boolean_template/src/features/settings/presentation/utils.dart'
5 | as utils;
6 | import 'package:flutter_boolean_template/src/features/settings/presentation/widgets/app_settings.dart';
7 |
8 | extension BuildContextSettings on BuildContext {
9 | Settings get settings => AppSettings.of(this);
10 | }
11 |
12 | extension BuildContextModalExtensions on BuildContext {
13 | Future showOptionsMenu({
14 | required OptionT current,
15 | required List options,
16 | required String title,
17 | }) async {
18 | return await utils.showOptionsMenu(
19 | this,
20 | current: current,
21 | options: options,
22 | title: title,
23 | );
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/lib/src/features/settings/presentation/screens/unknown_settings_screen.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class UnknownSettingsScreen extends StatelessWidget {
4 | const UnknownSettingsScreen({
5 | super.key,
6 | this.id,
7 | });
8 |
9 | final String? id;
10 |
11 | @override
12 | Widget build(BuildContext context) {
13 | return ColoredBox(
14 | color: Colors.redAccent,
15 | child: Center(child: Text(' ${id ?? 'Unknown'}Setting')),
16 | );
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/lib/src/features/settings/presentation/widgets/app_settings.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_boolean_template/src/features/settings/data/dto/settings.dart';
3 |
4 | class AppSettings extends InheritedModel {
5 | const AppSettings({
6 | required this.settings,
7 | required super.child,
8 | super.key,
9 | });
10 |
11 | final Settings settings;
12 |
13 | static Settings? maybeOf(BuildContext context) {
14 | return context.dependOnInheritedWidgetOfExactType()?.settings;
15 | }
16 |
17 | static Settings of(BuildContext context) {
18 | final Settings? result = maybeOf(context);
19 | assert(result != null, 'No AppSettings found in context');
20 | return result!;
21 | }
22 |
23 | @override
24 | bool updateShouldNotify(AppSettings oldWidget) =>
25 | settings != oldWidget.settings;
26 |
27 | @override
28 | bool updateShouldNotifyDependent(
29 | AppSettings oldWidget,
30 | Set dependencies,
31 | ) {
32 | return settings != oldWidget.settings && dependencies.contains('settings');
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/lib/src/routing/application/location_notifier.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_boolean_template/src/routing/router/router.dart';
2 | import 'package:hooks_riverpod/hooks_riverpod.dart';
3 |
4 | final locationProvider =
5 | NotifierProvider(LocationNotifier.new);
6 |
7 | /// Source: @cgestes https://github.com/flutter/flutter/issues/115353#issuecomment-1675808675
8 | class LocationNotifier extends Notifier {
9 | @override
10 | Uri build() {
11 | final router = ref.read(routerProvider);
12 | router.routerDelegate.addListener(onRouterDelegateChange);
13 | ref.onDispose(() {
14 | router.routerDelegate.removeListener(onRouterDelegateChange);
15 | });
16 | return router.locationUri;
17 | }
18 |
19 | void onRouterDelegateChange() {
20 | final routerDelegate = ref.read(routerProvider).routerDelegate;
21 | state = routerDelegate.locationUri;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/lib/src/routing/data/location_history.dart:
--------------------------------------------------------------------------------
1 | import 'package:dart_mappable/dart_mappable.dart';
2 |
3 | part 'location_history.mapper.dart';
4 |
5 | /// Source: @cgestes https://github.com/flutter/flutter/issues/115353#issuecomment-1675808675
6 | @MappableClass()
7 | class LocationHistory with LocationHistoryMappable {
8 | @MappableField()
9 | final List history;
10 | @MappableField()
11 | final List popped;
12 |
13 | /// Source: @cgestes https://github.com/flutter/flutter/issues/115353#issuecomment-1675808675
14 | const LocationHistory({
15 | this.history = const [],
16 | this.popped = const [],
17 | });
18 |
19 | bool hasForward() {
20 | return popped.isNotEmpty;
21 | }
22 |
23 | bool hasBackward() {
24 | return history.length > 1;
25 | }
26 |
27 | static const fromMap = LocationHistoryMapper.fromMap;
28 | static const fromJson = LocationHistoryMapper.fromJson;
29 | }
30 |
--------------------------------------------------------------------------------
/lib/src/routing/data/navigation_type.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_boolean_template/src/routing/presentation/widgets/responsive_sidebar.dart';
3 |
4 | /// The navigation mechanism to configure the [Scaffold] with.
5 | enum NavigationType {
6 | /// Used to configure a [Scaffold] with a [NavigationBar].
7 | bottom,
8 |
9 | /// Used to configure a [Scaffold] with a modal [Drawer].
10 | drawer,
11 |
12 | /// Used to configure a [Scaffold] with an open [ResponsiveSidebar].
13 | sidebar,
14 |
15 | /// (Experimental) Used to configure a [Scaffold] with a [TabBar]
16 | ///
17 | /// This does yet not support a title.
18 | top;
19 |
20 | bool get isSidebar {
21 | return this == NavigationType.sidebar;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/lib/src/routing/presentation/routes/book_details_route.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_boolean_template/src/features/books/presentation/book_details_screen.dart';
3 |
4 | class BookDetailsRoute extends StatefulWidget {
5 | const BookDetailsRoute({
6 | super.key,
7 | this.id,
8 | });
9 | final String? id;
10 |
11 | @override
12 | State createState() => _BookDetailsRouteState();
13 | }
14 |
15 | class _BookDetailsRouteState extends State {
16 | @override
17 | Widget build(BuildContext context) {
18 | return const BookDetailsScreen();
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/lib/src/routing/presentation/routes/books_route.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_boolean_template/src/features/books/presentation/books_screen.dart';
3 | import 'package:log/log.dart';
4 |
5 | class BooksRoute extends StatefulWidget {
6 | const BooksRoute({super.key});
7 |
8 | @override
9 | State createState() => _BooksRouteState();
10 | }
11 |
12 | class _BooksRouteState extends State {
13 | final log = Logger('BooksScreen');
14 |
15 | @override
16 | Widget build(BuildContext context) {
17 | return const BooksScreen();
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/lib/src/routing/presentation/routes/profile_details_route.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_boolean_template/src/features/profile/presentation/profile_details_screen.dart';
3 |
4 | class ProfileDetailsRoute extends StatefulWidget {
5 | const ProfileDetailsRoute({super.key});
6 |
7 | @override
8 | State createState() => _ProfileDetailsRouteState();
9 | }
10 |
11 | class _ProfileDetailsRouteState extends State {
12 | @override
13 | Widget build(BuildContext context) {
14 | return const ProfileDetailsScreen();
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/lib/src/routing/presentation/routes/profile_route.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_boolean_template/src/features/profile/presentation/profile_screen.dart';
3 |
4 | class ProfileRoute extends StatefulWidget {
5 | const ProfileRoute({super.key});
6 |
7 | @override
8 | State createState() => _ProfileRouteState();
9 | }
10 |
11 | class _ProfileRouteState extends State {
12 | @override
13 | Widget build(BuildContext context) {
14 | return const ProfileScreen();
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/lib/src/routing/presentation/routes/setting_details_route.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_boolean_template/src/features/settings/presentation/screens/about_settings_screen.dart';
3 | import 'package:flutter_boolean_template/src/features/settings/presentation/screens/appearance_settings_screen.dart';
4 | import 'package:flutter_boolean_template/src/features/settings/presentation/screens/unknown_settings_screen.dart';
5 |
6 | class SettingDetailsRoute extends StatefulWidget {
7 | const SettingDetailsRoute({super.key, this.id});
8 |
9 | final String? id;
10 |
11 | @override
12 | State createState() => _SettingDetailsRouteState();
13 | }
14 |
15 | class _SettingDetailsRouteState extends State {
16 | @override
17 | Widget build(BuildContext context) {
18 | return switch (widget.id) {
19 | 'about' => const AboutSettingsScreen(),
20 | 'appearance' => const AppearanceSettingsScreen(),
21 | _ => UnknownSettingsScreen(id: widget.id)
22 | };
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/lib/src/routing/presentation/routes/settings_route.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_boolean_template/src/features/settings/presentation/screens/settings_screen.dart';
3 |
4 | class SettingsRoute extends StatefulWidget {
5 | const SettingsRoute({super.key});
6 |
7 | @override
8 | State createState() => _SettingsRouteState();
9 | }
10 |
11 | class _SettingsRouteState extends State {
12 | @override
13 | Widget build(BuildContext context) {
14 | return const SettingsScreen();
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/lib/src/routing/presentation/widgets/router_widget.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_boolean_template/src/routing/router/router.dart';
3 | import 'package:hooks_riverpod/hooks_riverpod.dart';
4 |
5 | class RouterWidget extends ConsumerWidget {
6 | const RouterWidget({required this.builder, super.key});
7 |
8 | final Widget Function(BuildContext, RouterConfig