├── example ├── ios │ ├── Runner │ │ ├── Runner-Bridging-Header.h │ │ ├── Assets.xcassets │ │ │ ├── LaunchImage.imageset │ │ │ │ ├── LaunchImage.png │ │ │ │ ├── LaunchImage@2x.png │ │ │ │ ├── LaunchImage@3x.png │ │ │ │ ├── README.md │ │ │ │ └── Contents.json │ │ │ └── AppIcon.appiconset │ │ │ │ ├── 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-1024x1024@1x.png │ │ │ │ ├── Icon-App-83.5x83.5@2x.png │ │ │ │ └── Contents.json │ │ ├── AppDelegate.swift │ │ ├── Base.lproj │ │ │ ├── Main.storyboard │ │ │ └── LaunchScreen.storyboard │ │ └── Info.plist │ ├── Flutter │ │ ├── Debug.xcconfig │ │ ├── Release.xcconfig │ │ └── AppFrameworkInfo.plist │ ├── Runner.xcodeproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ │ └── IDEWorkspaceChecks.plist │ │ ├── xcshareddata │ │ │ └── xcschemes │ │ │ │ └── Runner.xcscheme │ │ └── project.pbxproj │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ └── IDEWorkspaceChecks.plist │ ├── Podfile.lock │ ├── .gitignore │ └── Podfile ├── android │ ├── gradle.properties │ ├── app │ │ ├── src │ │ │ ├── main │ │ │ │ ├── res │ │ │ │ │ ├── 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 │ │ │ │ │ ├── drawable │ │ │ │ │ │ └── launch_background.xml │ │ │ │ │ ├── drawable-v21 │ │ │ │ │ │ └── launch_background.xml │ │ │ │ │ ├── values │ │ │ │ │ │ └── styles.xml │ │ │ │ │ └── values-night │ │ │ │ │ │ └── styles.xml │ │ │ │ ├── kotlin │ │ │ │ │ └── com │ │ │ │ │ │ └── hamidwakili │ │ │ │ │ │ └── another_flushbar_example │ │ │ │ │ │ └── MainActivity.kt │ │ │ │ └── AndroidManifest.xml │ │ │ ├── debug │ │ │ │ └── AndroidManifest.xml │ │ │ └── profile │ │ │ │ └── AndroidManifest.xml │ │ └── build.gradle │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ ├── .gitignore │ ├── settings.gradle │ └── build.gradle ├── .metadata ├── README.md ├── .gitignore ├── test │ └── widget_test.dart ├── pubspec.yaml ├── pubspec.lock └── lib │ └── main.dart ├── .gitignore ├── android ├── local.properties ├── app │ └── src │ │ └── main │ │ └── java │ │ └── io │ │ └── flutter │ │ └── plugins │ │ └── GeneratedPluginRegistrant.java └── another_flushbar_android.iml ├── readme_resources ├── rtl_bar.png ├── basic_bar.png ├── input_bar.png ├── text_bar.png ├── complete_bar.png ├── gradient_bar.png ├── position_bar.png ├── floating_style.png ├── flushbar_logo.png ├── grounded_style.png ├── flushbar_animated.gif ├── background_color_bar.png ├── icon_and_button_bar.png ├── left_bar_indicator.png └── padding_and_radius.png ├── analysis_options.yaml ├── .metadata ├── LICENSE ├── pubspec.yaml ├── test └── another_flushbar_test.dart ├── lib ├── flushbar_helper.dart ├── flushbar_route.dart └── flushbar.dart ├── pubspec.lock ├── CHANGELOG.md └── README.md /example/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .dart_tool/ 3 | 4 | .packages 5 | .pub/ 6 | 7 | build/ 8 | 9 | .idea/ -------------------------------------------------------------------------------- /android/local.properties: -------------------------------------------------------------------------------- 1 | sdk.dir=/home/slayer/Android/Sdk 2 | flutter.sdk=/home/slayer/snap/flutter/common/flutter -------------------------------------------------------------------------------- /readme_resources/rtl_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/X-SLAYER/another-flushbar/main/readme_resources/rtl_bar.png -------------------------------------------------------------------------------- /readme_resources/basic_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/X-SLAYER/another-flushbar/main/readme_resources/basic_bar.png -------------------------------------------------------------------------------- /readme_resources/input_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/X-SLAYER/another-flushbar/main/readme_resources/input_bar.png -------------------------------------------------------------------------------- /readme_resources/text_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/X-SLAYER/another-flushbar/main/readme_resources/text_bar.png -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /readme_resources/complete_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/X-SLAYER/another-flushbar/main/readme_resources/complete_bar.png -------------------------------------------------------------------------------- /readme_resources/gradient_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/X-SLAYER/another-flushbar/main/readme_resources/gradient_bar.png -------------------------------------------------------------------------------- /readme_resources/position_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/X-SLAYER/another-flushbar/main/readme_resources/position_bar.png -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml 2 | linter: 3 | rules: 4 | constant_identifier_names: false -------------------------------------------------------------------------------- /readme_resources/floating_style.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/X-SLAYER/another-flushbar/main/readme_resources/floating_style.png -------------------------------------------------------------------------------- /readme_resources/flushbar_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/X-SLAYER/another-flushbar/main/readme_resources/flushbar_logo.png -------------------------------------------------------------------------------- /readme_resources/grounded_style.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/X-SLAYER/another-flushbar/main/readme_resources/grounded_style.png -------------------------------------------------------------------------------- /readme_resources/flushbar_animated.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/X-SLAYER/another-flushbar/main/readme_resources/flushbar_animated.gif -------------------------------------------------------------------------------- /readme_resources/background_color_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/X-SLAYER/another-flushbar/main/readme_resources/background_color_bar.png -------------------------------------------------------------------------------- /readme_resources/icon_and_button_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/X-SLAYER/another-flushbar/main/readme_resources/icon_and_button_bar.png -------------------------------------------------------------------------------- /readme_resources/left_bar_indicator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/X-SLAYER/another-flushbar/main/readme_resources/left_bar_indicator.png -------------------------------------------------------------------------------- /readme_resources/padding_and_radius.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/X-SLAYER/another-flushbar/main/readme_resources/padding_and_radius.png -------------------------------------------------------------------------------- /example/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/X-SLAYER/another-flushbar/main/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/X-SLAYER/another-flushbar/main/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/X-SLAYER/another-flushbar/main/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/X-SLAYER/another-flushbar/main/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/X-SLAYER/another-flushbar/main/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/X-SLAYER/another-flushbar/main/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/X-SLAYER/another-flushbar/main/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/X-SLAYER/another-flushbar/main/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/X-SLAYER/another-flushbar/main/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/X-SLAYER/another-flushbar/main/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/X-SLAYER/another-flushbar/main/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/X-SLAYER/another-flushbar/main/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/X-SLAYER/another-flushbar/main/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/X-SLAYER/another-flushbar/main/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/X-SLAYER/another-flushbar/main/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/X-SLAYER/another-flushbar/main/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/X-SLAYER/another-flushbar/main/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/X-SLAYER/another-flushbar/main/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/X-SLAYER/another-flushbar/main/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/X-SLAYER/another-flushbar/main/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/X-SLAYER/another-flushbar/main/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/X-SLAYER/another-flushbar/main/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/X-SLAYER/another-flushbar/main/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/app/src/main/kotlin/com/hamidwakili/another_flushbar_example/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.hamidwakili.another_flushbar_example 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip 7 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.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: c6290500f827e006858ef2d17081b363949f6ce0 8 | channel: master 9 | 10 | project_type: plugin 11 | -------------------------------------------------------------------------------- /example/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: c6290500f827e006858ef2d17081b363949f6ce0 8 | channel: master 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /example/ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Flutter (1.0.0) 3 | 4 | DEPENDENCIES: 5 | - Flutter (from `Flutter`) 6 | 7 | EXTERNAL SOURCES: 8 | Flutter: 9 | :path: Flutter 10 | 11 | SPEC CHECKSUMS: 12 | Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a 13 | 14 | PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c 15 | 16 | COCOAPODS: 1.10.0 17 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 4 | def properties = new Properties() 5 | 6 | assert localPropertiesFile.exists() 7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 8 | 9 | def flutterSdkPath = properties.getProperty("flutter.sdk") 10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 12 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright [2018-2020] [André Haueisen Batista de Lima, Hamid Wakili] 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # another_flushbar_example 2 | 3 | Demonstrates how to use the another_flushbar plugin. 4 | 5 | ## Getting Started 6 | 7 | This project is a starting point for a Flutter application. 8 | 9 | A few resources to get you started if this is your first Flutter project: 10 | 11 | - [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) 12 | - [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) 13 | 14 | For help getting started with Flutter, view our 15 | [online documentation](https://flutter.dev/docs), which offers tutorials, 16 | samples, guidance on mobile development, and a full API reference. 17 | -------------------------------------------------------------------------------- /example/ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/app.flx 22 | Flutter/app.zip 23 | Flutter/flutter_assets/ 24 | Flutter/flutter_export_environment.sh 25 | ServiceDefinitions.json 26 | Runner/GeneratedPluginRegistrant.* 27 | 28 | # Exceptions to above rules. 29 | !default.mode1v3 30 | !default.mode2v3 31 | !default.pbxuser 32 | !default.perspectivev3 33 | -------------------------------------------------------------------------------- /android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java: -------------------------------------------------------------------------------- 1 | package io.flutter.plugins; 2 | 3 | import io.flutter.plugin.common.PluginRegistry; 4 | 5 | /** 6 | * Generated file. Do not edit. 7 | */ 8 | public final class GeneratedPluginRegistrant { 9 | public static void registerWith(PluginRegistry registry) { 10 | if (alreadyRegisteredWith(registry)) { 11 | return; 12 | } 13 | } 14 | 15 | private static boolean alreadyRegisteredWith(PluginRegistry registry) { 16 | final String key = GeneratedPluginRegistrant.class.getCanonicalName(); 17 | if (registry.hasPlugin(key)) { 18 | return true; 19 | } 20 | registry.registrarFor(key); 21 | return false; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.3.50' 3 | repositories { 4 | google() 5 | jcenter() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:3.5.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | jcenter() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | } 25 | subprojects { 26 | project.evaluationDependsOn(':app') 27 | } 28 | 29 | task clean(type: Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /example/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 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 | 9.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Web related 35 | lib/generated_plugin_registrant.dart 36 | 37 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | 43 | # Android Studio will place build artifacts here 44 | /android/app/debug 45 | /android/app/profile 46 | /android/app/release 47 | -------------------------------------------------------------------------------- /example/test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:another_flushbar_example/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Verify Platform version', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(MyApp()); 17 | 18 | // Verify that platform version is retrieved. 19 | expect( 20 | find.byWidgetPredicate( 21 | (Widget widget) => 22 | widget is Text && widget.data.startsWith('Running on:'), 23 | ), 24 | findsOneWidget, 25 | ); 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/another_flushbar_android.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /example/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | use_frameworks! 32 | use_modular_headers! 33 | 34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 35 | end 36 | 37 | post_install do |installer| 38 | installer.pods_project.targets.each do |target| 39 | flutter_additional_ios_build_settings(target) 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | another_flushbar_example 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: another_flushbar 2 | description: A flexible widget for user notification. Customize your text, button, duration, animations and much more. For Android devs, it is made to replace Snackbars and Toasts. 3 | version: 1.10.27 4 | homepage: https://github.com/cmdrootaccess/another-flushbar 5 | 6 | environment: 7 | sdk: '>=2.12.0 <3.0.0' 8 | 9 | dependencies: 10 | flutter: 11 | sdk: flutter 12 | 13 | dev_dependencies: 14 | flutter_lints: ^1.0.4 15 | flutter_test: 16 | sdk: flutter 17 | 18 | # For information on the generic Dart part of this file, see the 19 | # following page: https://dart.dev/tools/pub/pubspec 20 | 21 | # The following section is specific to Flutter. 22 | flutter: 23 | 24 | # To add assets to your plugin package, add an assets section, like this: 25 | # assets: 26 | # - images/a_dot_burr.jpeg 27 | # - images/a_dot_ham.jpeg 28 | # 29 | # For details regarding assets in packages, see 30 | # https://flutter.dev/assets-and-images/#from-packages 31 | # 32 | # An image asset can refer to one or more resolution-specific "variants", see 33 | # https://flutter.dev/assets-and-images/#resolution-aware. 34 | 35 | # To add custom fonts to your plugin package, add a fonts section here, 36 | # in this "flutter" section. Each entry in this list should have a 37 | # "family" key with the font family name, and a "fonts" key with a 38 | # list giving the asset and other descriptors for the font. For 39 | # example: 40 | # fonts: 41 | # - family: Schyler 42 | # fonts: 43 | # - asset: fonts/Schyler-Regular.ttf 44 | # - asset: fonts/Schyler-Italic.ttf 45 | # style: italic 46 | # - family: Trajan Pro 47 | # fonts: 48 | # - asset: fonts/TrajanPro.ttf 49 | # - asset: fonts/TrajanPro_Bold.ttf 50 | # weight: 700 51 | # 52 | # For details regarding fonts in packages, see 53 | # https://flutter.dev/custom-fonts/#from-packages 54 | -------------------------------------------------------------------------------- /example/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | android { 29 | compileSdkVersion 29 30 | 31 | sourceSets { 32 | main.java.srcDirs += 'src/main/kotlin' 33 | } 34 | 35 | lintOptions { 36 | disable 'InvalidPackage' 37 | } 38 | 39 | defaultConfig { 40 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 41 | applicationId "com.hamidwakili.another_flushbar_example" 42 | minSdkVersion 16 43 | targetSdkVersion 29 44 | versionCode flutterVersionCode.toInteger() 45 | versionName flutterVersionName 46 | } 47 | 48 | buildTypes { 49 | release { 50 | // TODO: Add your own signing config for the release build. 51 | // Signing with the debug keys for now, so `flutter run --release` works. 52 | signingConfig signingConfigs.debug 53 | } 54 | } 55 | } 56 | 57 | flutter { 58 | source '../..' 59 | } 60 | 61 | dependencies { 62 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 63 | } 64 | -------------------------------------------------------------------------------- /test/another_flushbar_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_test/flutter_test.dart'; 2 | import 'package:another_flushbar/flushbar.dart'; 3 | 4 | import 'package:flutter/material.dart'; 5 | import 'package:flutter/widgets.dart'; 6 | 7 | void main() { 8 | TestWidgetsFlutterBinding.ensureInitialized(); 9 | 10 | test('Test Flushbar basic inicialization', () async { 11 | final flushbar = Flushbar(message: 'This is a test'); 12 | expect(flushbar.title, null); 13 | expect(flushbar.message, 'This is a test'); 14 | expect(flushbar.duration, null); 15 | expect(flushbar.backgroundColor, const Color(0xFF303030)); 16 | expect(flushbar.flushbarPosition, FlushbarPosition.BOTTOM); 17 | expect(flushbar.flushbarStyle, FlushbarStyle.FLOATING); 18 | expect(flushbar.forwardAnimationCurve, Curves.easeOutCirc); 19 | expect(flushbar.reverseAnimationCurve, Curves.easeOutCirc); 20 | expect(flushbar.titleText, null); 21 | expect(flushbar.messageText, null); 22 | expect(flushbar.icon, null); 23 | expect(flushbar.leftBarIndicatorColor, null); 24 | expect(flushbar.boxShadows, null); 25 | expect(flushbar.backgroundGradient, null); 26 | expect(flushbar.mainButton, null); 27 | expect(flushbar.borderRadius, null); 28 | expect(flushbar.borderWidth, 1.0); 29 | expect(flushbar.borderColor, null); 30 | expect(flushbar.padding.left, 16); 31 | expect(flushbar.padding.right, 16); 32 | expect(flushbar.padding.top, 16); 33 | expect(flushbar.padding.bottom, 16); 34 | expect(flushbar.margin.left, 0); 35 | expect(flushbar.margin.right, 0); 36 | expect(flushbar.margin.top, 0); 37 | expect(flushbar.margin.bottom, 0); 38 | expect(flushbar.onTap, null); 39 | expect(flushbar.isDismissible, true); 40 | expect(flushbar.dismissDirection, FlushbarDismissDirection.VERTICAL); 41 | expect(flushbar.showProgressIndicator, false); 42 | expect(flushbar.progressIndicatorController, null); 43 | expect(flushbar.progressIndicatorBackgroundColor, null); 44 | expect(flushbar.progressIndicatorValueColor, null); 45 | expect(flushbar.routeBlur, null); 46 | expect(flushbar.routeColor, null); 47 | }); 48 | } 49 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 13 | 17 | 21 | 26 | 30 | 31 | 32 | 33 | 34 | 35 | 37 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: another_flushbar_example 2 | description: Demonstrates how to use the another_flushbar plugin. 3 | 4 | # The following line prevents the package from being accidentally published to 5 | # pub.dev using `pub publish`. This is preferred for private packages. 6 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev 7 | 8 | environment: 9 | sdk: ">=2.7.0 <3.0.0" 10 | 11 | dependencies: 12 | flutter: 13 | sdk: flutter 14 | 15 | another_flushbar: 16 | # When depending on this package from a real application you should use: 17 | # another_flushbar: ^x.y.z 18 | # See https://dart.dev/tools/pub/dependencies#version-constraints 19 | # The example app is bundled with the plugin so we use a path dependency on 20 | # the parent directory to use the current plugin's version. 21 | path: ../ 22 | 23 | # The following adds the Cupertino Icons font to your application. 24 | # Use with the CupertinoIcons class for iOS style icons. 25 | cupertino_icons: ^1.0.1 26 | 27 | dev_dependencies: 28 | flutter_test: 29 | sdk: flutter 30 | 31 | # For information on the generic Dart part of this file, see the 32 | # following page: https://dart.dev/tools/pub/pubspec 33 | 34 | # The following section is specific to Flutter. 35 | flutter: 36 | 37 | # The following line ensures that the Material Icons font is 38 | # included with your application, so that you can use the icons in 39 | # the material Icons class. 40 | uses-material-design: true 41 | 42 | # To add assets to your application, add an assets section, like this: 43 | # assets: 44 | # - images/a_dot_burr.jpeg 45 | # - images/a_dot_ham.jpeg 46 | 47 | # An image asset can refer to one or more resolution-specific "variants", see 48 | # https://flutter.dev/assets-and-images/#resolution-aware. 49 | 50 | # For details regarding adding assets from package dependencies, see 51 | # https://flutter.dev/assets-and-images/#from-packages 52 | 53 | # To add custom fonts to your application, add a fonts section here, 54 | # in this "flutter" section. Each entry in this list should have a 55 | # "family" key with the font family name, and a "fonts" key with a 56 | # list giving the asset and other descriptors for the font. For 57 | # example: 58 | # fonts: 59 | # - family: Schyler 60 | # fonts: 61 | # - asset: fonts/Schyler-Regular.ttf 62 | # - asset: fonts/Schyler-Italic.ttf 63 | # style: italic 64 | # - family: Trajan Pro 65 | # fonts: 66 | # - asset: fonts/TrajanPro.ttf 67 | # - asset: fonts/TrajanPro_Bold.ttf 68 | # weight: 700 69 | # 70 | # For details regarding fonts from package dependencies, 71 | # see https://flutter.dev/custom-fonts/#from-packages 72 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /lib/flushbar_helper.dart: -------------------------------------------------------------------------------- 1 | import 'flushbar.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class FlushbarHelper { 5 | /// Get a success notification flushbar. 6 | static Flushbar createSuccess( 7 | {required String message, 8 | String? title, 9 | Duration duration = const Duration(seconds: 3)}) { 10 | return Flushbar( 11 | title: title, 12 | message: message, 13 | icon: Icon( 14 | Icons.check_circle, 15 | color: Colors.green[300], 16 | ), 17 | leftBarIndicatorColor: Colors.green[300], 18 | duration: duration, 19 | ); 20 | } 21 | 22 | /// Get an information notification flushbar 23 | static Flushbar createInformation( 24 | {required String message, 25 | String? title, 26 | Duration duration = const Duration(seconds: 3)}) { 27 | return Flushbar( 28 | title: title, 29 | message: message, 30 | icon: Icon( 31 | Icons.info_outline, 32 | size: 28.0, 33 | color: Colors.blue[300], 34 | ), 35 | leftBarIndicatorColor: Colors.blue[300], 36 | duration: duration, 37 | ); 38 | } 39 | 40 | /// Get a error notification flushbar 41 | static Flushbar createError( 42 | {required String message, 43 | String? title, 44 | Duration duration = const Duration(seconds: 3)}) { 45 | return Flushbar( 46 | title: title, 47 | message: message, 48 | icon: Icon( 49 | Icons.warning, 50 | size: 28.0, 51 | color: Colors.red[300], 52 | ), 53 | leftBarIndicatorColor: Colors.red[300], 54 | duration: duration, 55 | ); 56 | } 57 | 58 | /// Get a flushbar that can receive a user action through a button. 59 | static Flushbar createAction( 60 | {required String message, 61 | required Widget button, 62 | String? title, 63 | Duration duration = const Duration(seconds: 3)}) { 64 | return Flushbar( 65 | title: title, 66 | message: message, 67 | duration: duration, 68 | mainButton: button, 69 | ); 70 | } 71 | 72 | // Get a flushbar that shows the progress of a async computation. 73 | static Flushbar createLoading( 74 | {required String message, 75 | required LinearProgressIndicator linearProgressIndicator, 76 | String? title, 77 | Duration duration = const Duration(seconds: 3), 78 | AnimationController? progressIndicatorController, 79 | Color? progressIndicatorBackgroundColor}) { 80 | return Flushbar( 81 | title: title, 82 | message: message, 83 | icon: Icon( 84 | Icons.cloud_upload, 85 | color: Colors.blue[300], 86 | ), 87 | duration: duration, 88 | showProgressIndicator: true, 89 | progressIndicatorController: progressIndicatorController, 90 | progressIndicatorBackgroundColor: progressIndicatorBackgroundColor, 91 | ); 92 | } 93 | 94 | /// Get a flushbar that shows an user input form. 95 | static Flushbar createInputFlushbar({required Form textForm}) { 96 | return Flushbar( 97 | duration: null, 98 | userInputForm: textForm, 99 | ); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "2.8.2" 11 | boolean_selector: 12 | dependency: transitive 13 | description: 14 | name: boolean_selector 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "2.1.0" 18 | characters: 19 | dependency: transitive 20 | description: 21 | name: characters 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "1.2.0" 25 | charcode: 26 | dependency: transitive 27 | description: 28 | name: charcode 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "1.3.1" 32 | clock: 33 | dependency: transitive 34 | description: 35 | name: clock 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "1.1.0" 39 | collection: 40 | dependency: transitive 41 | description: 42 | name: collection 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "1.16.0" 46 | fake_async: 47 | dependency: transitive 48 | description: 49 | name: fake_async 50 | url: "https://pub.dartlang.org" 51 | source: hosted 52 | version: "1.3.0" 53 | flutter: 54 | dependency: "direct main" 55 | description: flutter 56 | source: sdk 57 | version: "0.0.0" 58 | flutter_lints: 59 | dependency: "direct dev" 60 | description: 61 | name: flutter_lints 62 | url: "https://pub.dartlang.org" 63 | source: hosted 64 | version: "1.0.4" 65 | flutter_test: 66 | dependency: "direct dev" 67 | description: flutter 68 | source: sdk 69 | version: "0.0.0" 70 | lints: 71 | dependency: transitive 72 | description: 73 | name: lints 74 | url: "https://pub.dartlang.org" 75 | source: hosted 76 | version: "1.0.1" 77 | matcher: 78 | dependency: transitive 79 | description: 80 | name: matcher 81 | url: "https://pub.dartlang.org" 82 | source: hosted 83 | version: "0.12.11" 84 | material_color_utilities: 85 | dependency: transitive 86 | description: 87 | name: material_color_utilities 88 | url: "https://pub.dartlang.org" 89 | source: hosted 90 | version: "0.1.4" 91 | meta: 92 | dependency: transitive 93 | description: 94 | name: meta 95 | url: "https://pub.dartlang.org" 96 | source: hosted 97 | version: "1.7.0" 98 | path: 99 | dependency: transitive 100 | description: 101 | name: path 102 | url: "https://pub.dartlang.org" 103 | source: hosted 104 | version: "1.8.1" 105 | sky_engine: 106 | dependency: transitive 107 | description: flutter 108 | source: sdk 109 | version: "0.0.99" 110 | source_span: 111 | dependency: transitive 112 | description: 113 | name: source_span 114 | url: "https://pub.dartlang.org" 115 | source: hosted 116 | version: "1.8.2" 117 | stack_trace: 118 | dependency: transitive 119 | description: 120 | name: stack_trace 121 | url: "https://pub.dartlang.org" 122 | source: hosted 123 | version: "1.10.0" 124 | stream_channel: 125 | dependency: transitive 126 | description: 127 | name: stream_channel 128 | url: "https://pub.dartlang.org" 129 | source: hosted 130 | version: "2.1.0" 131 | string_scanner: 132 | dependency: transitive 133 | description: 134 | name: string_scanner 135 | url: "https://pub.dartlang.org" 136 | source: hosted 137 | version: "1.1.0" 138 | term_glyph: 139 | dependency: transitive 140 | description: 141 | name: term_glyph 142 | url: "https://pub.dartlang.org" 143 | source: hosted 144 | version: "1.2.0" 145 | test_api: 146 | dependency: transitive 147 | description: 148 | name: test_api 149 | url: "https://pub.dartlang.org" 150 | source: hosted 151 | version: "0.4.9" 152 | vector_math: 153 | dependency: transitive 154 | description: 155 | name: vector_math 156 | url: "https://pub.dartlang.org" 157 | source: hosted 158 | version: "2.1.2" 159 | sdks: 160 | dart: ">=2.17.0-0 <3.0.0" 161 | -------------------------------------------------------------------------------- /example/pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | another_flushbar: 5 | dependency: "direct main" 6 | description: 7 | path: ".." 8 | relative: true 9 | source: path 10 | version: "1.10.27" 11 | async: 12 | dependency: transitive 13 | description: 14 | name: async 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "2.8.2" 18 | boolean_selector: 19 | dependency: transitive 20 | description: 21 | name: boolean_selector 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "2.1.0" 25 | characters: 26 | dependency: transitive 27 | description: 28 | name: characters 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "1.2.0" 32 | charcode: 33 | dependency: transitive 34 | description: 35 | name: charcode 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "1.3.1" 39 | clock: 40 | dependency: transitive 41 | description: 42 | name: clock 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "1.1.0" 46 | collection: 47 | dependency: transitive 48 | description: 49 | name: collection 50 | url: "https://pub.dartlang.org" 51 | source: hosted 52 | version: "1.16.0" 53 | cupertino_icons: 54 | dependency: "direct main" 55 | description: 56 | name: cupertino_icons 57 | url: "https://pub.dartlang.org" 58 | source: hosted 59 | version: "1.0.3" 60 | fake_async: 61 | dependency: transitive 62 | description: 63 | name: fake_async 64 | url: "https://pub.dartlang.org" 65 | source: hosted 66 | version: "1.3.0" 67 | flutter: 68 | dependency: "direct main" 69 | description: flutter 70 | source: sdk 71 | version: "0.0.0" 72 | flutter_test: 73 | dependency: "direct dev" 74 | description: flutter 75 | source: sdk 76 | version: "0.0.0" 77 | matcher: 78 | dependency: transitive 79 | description: 80 | name: matcher 81 | url: "https://pub.dartlang.org" 82 | source: hosted 83 | version: "0.12.11" 84 | material_color_utilities: 85 | dependency: transitive 86 | description: 87 | name: material_color_utilities 88 | url: "https://pub.dartlang.org" 89 | source: hosted 90 | version: "0.1.4" 91 | meta: 92 | dependency: transitive 93 | description: 94 | name: meta 95 | url: "https://pub.dartlang.org" 96 | source: hosted 97 | version: "1.7.0" 98 | path: 99 | dependency: transitive 100 | description: 101 | name: path 102 | url: "https://pub.dartlang.org" 103 | source: hosted 104 | version: "1.8.1" 105 | sky_engine: 106 | dependency: transitive 107 | description: flutter 108 | source: sdk 109 | version: "0.0.99" 110 | source_span: 111 | dependency: transitive 112 | description: 113 | name: source_span 114 | url: "https://pub.dartlang.org" 115 | source: hosted 116 | version: "1.8.2" 117 | stack_trace: 118 | dependency: transitive 119 | description: 120 | name: stack_trace 121 | url: "https://pub.dartlang.org" 122 | source: hosted 123 | version: "1.10.0" 124 | stream_channel: 125 | dependency: transitive 126 | description: 127 | name: stream_channel 128 | url: "https://pub.dartlang.org" 129 | source: hosted 130 | version: "2.1.0" 131 | string_scanner: 132 | dependency: transitive 133 | description: 134 | name: string_scanner 135 | url: "https://pub.dartlang.org" 136 | source: hosted 137 | version: "1.1.0" 138 | term_glyph: 139 | dependency: transitive 140 | description: 141 | name: term_glyph 142 | url: "https://pub.dartlang.org" 143 | source: hosted 144 | version: "1.2.0" 145 | test_api: 146 | dependency: transitive 147 | description: 148 | name: test_api 149 | url: "https://pub.dartlang.org" 150 | source: hosted 151 | version: "0.4.9" 152 | vector_math: 153 | dependency: transitive 154 | description: 155 | name: vector_math 156 | url: "https://pub.dartlang.org" 157 | source: hosted 158 | version: "2.1.2" 159 | sdks: 160 | dart: ">=2.17.0-0 <3.0.0" 161 | -------------------------------------------------------------------------------- /example/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:another_flushbar/flushbar.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | void main() { 5 | runApp(MyApp()); 6 | } 7 | 8 | class MyApp extends StatelessWidget { 9 | // This widget is the root of your application. 10 | @override 11 | Widget build(BuildContext context) { 12 | return MaterialApp( 13 | title: 'Flutter Demo', 14 | theme: ThemeData( 15 | // This is the theme of your application. 16 | // 17 | // Try running your application with "flutter run". You'll see the 18 | // application has a blue toolbar. Then, without quitting the app, try 19 | // changing the primarySwatch below to Colors.green and then invoke 20 | // "hot reload" (press "r" in the console where you ran "flutter run", 21 | // or simply save your changes to "hot reload" in a Flutter IDE). 22 | // Notice that the counter didn't reset back to zero; the application 23 | // is not restarted. 24 | primarySwatch: Colors.blue, 25 | ), 26 | home: MyHomePage(title: 'Flutter Demo Home Page'), 27 | ); 28 | } 29 | } 30 | 31 | class MyHomePage extends StatefulWidget { 32 | MyHomePage({Key key, this.title}) : super(key: key); 33 | 34 | // This widget is the home page of your application. It is stateful, meaning 35 | // that it has a State object (defined below) that contains fields that affect 36 | // how it looks. 37 | 38 | // This class is the configuration for the state. It holds the values (in this 39 | // case the title) provided by the parent (in this case the App widget) and 40 | // used by the build method of the State. Fields in a Widget subclass are 41 | // always marked "final". 42 | 43 | final String title; 44 | 45 | @override 46 | _MyHomePageState createState() => _MyHomePageState(); 47 | } 48 | 49 | class _MyHomePageState extends State { 50 | @override 51 | Widget build(BuildContext context) { 52 | // This method is rerun every time setState is called, for instance as done 53 | // by the _incrementCounter method above. 54 | // 55 | // The Flutter framework has been optimized to make rerunning build methods 56 | // fast, so that you can just rebuild anything that needs updating rather 57 | // than having to individually change instances of widgets. 58 | return Scaffold( 59 | appBar: AppBar( 60 | // Here we take the value from the MyHomePage object that was created by 61 | // the App.build method, and use it to set our appbar title. 62 | title: Text(widget.title), 63 | ), 64 | body: Center( 65 | // Center is a layout widget. It takes a single child and positions it 66 | // in the middle of the parent. 67 | child: Column( 68 | // Column is also a layout widget. It takes a list of children and 69 | // arranges them vertically. By default, it sizes itself to fit its 70 | // children horizontally, and tries to be as tall as its parent. 71 | // 72 | // Invoke "debug painting" (press "p" in the console, choose the 73 | // "Toggle Debug Paint" action from the Flutter Inspector in Android 74 | // Studio, or the "Toggle Debug Paint" command in Visual Studio Code) 75 | // to see the wireframe for each widget. 76 | // 77 | // Column has various properties to control how it sizes itself and 78 | // how it positions its children. Here we use mainAxisAlignment to 79 | // center the children vertically; the main axis here is the vertical 80 | // axis because Columns are vertical (the cross axis would be 81 | // horizontal). 82 | mainAxisAlignment: MainAxisAlignment.center, 83 | children: [ 84 | Text( 85 | 'Hello flushbar:', 86 | ), 87 | ], 88 | ), 89 | ), 90 | floatingActionButton: FloatingActionButton( 91 | onPressed: () async { 92 | await Flushbar( 93 | title: 'Hey Ninja', 94 | message: 95 | 'Lorem Ipsum is simply dummy text of the printing and typesetting industry', 96 | duration: Duration(seconds: 3), 97 | ).show(context); 98 | }, 99 | tooltip: 'Increment', 100 | child: Icon(Icons.add), 101 | ), // This trailing comma makes auto-formatting nicer for build methods. 102 | ); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.10.27 - 2021-12-09 2 | - merge updates 3 | ## 1.10.26 - 2021-11-24 4 | - Update screenshot links 5 | ## 1.10.25 - 2021-11-01 6 | - RTL text 7 | ## 1.10.24 - 2021-07-6 8 | - Implemented endOffset parameter 9 | ## 1.10.23 - 2021-06-4 10 | - Prevents hiding flushbar when user clicks the back button. 11 | ## 1.10.22 - 2021-05-14 12 | - check if flushbar is null 13 | ## 1.10.21 - 2021-05-14 14 | - add radius to leftBarIndicatorColor 15 | ## 1.10.20 - 2021-04-24 16 | - If route was never initialized, do nothing 17 | ## 1.10.19 - 2021-04-23 18 | - Fix Flushbar is hidden behind keyboard 19 | ## 1.10.18 - 2021-04-16 20 | - Fix LateInitializationError: Field '_progressListener' has not been initialized 21 | ## 1.10.17 - 2021-03-16 22 | - Fix nullpointer on onStatusChanged & add pedantic analysis and formatting 23 | ## 1.10.16 - 2021-03-16 24 | - Remove unnecessary platform specific code 25 | ## 1.10.15 - 2021-03-11 26 | - Add isAppearing and isHiding methods 27 | ## 1.10.14 - 2021-03-10 28 | - add color and size parameter 29 | - Let the user choose which corner they want to apply a radius on. 30 | ## 1.10.13 - 2021-03-6 31 | - fix Expected value of SkDeletable, but got one of type Null 32 | - fix regression after merge generated_plugin_registrant.dart: Undefined name 'AnotherFlushbarPlugin 33 | ## 1.10.12 - 2021-03-6 34 | - added null safety support after merge from areille/null-safety merge 35 | ## 1.10.11 - 2021-02-22 36 | - fix [WEB] Undefined name 'AnotherFlushbarPlugin' in generated_plugin_registrant.dart 37 | ## 1.10.10 - 2021-02-16 38 | - FlushbarHelper.createAction() "button" parameter takes a FlatButton which is now deprecated in favor of TextButton 39 | ## 1.10.9 - 2021-02-16 40 | - added positionOffset which allows a vertical offset for the flushbar 41 | ## 1.10.8 - 2020-12-12 42 | - Web support 43 | ## 1.10.7 - 2020-06-12 44 | - Updated Example 45 | 46 | ## 1.10.6 - 2020-06-12 47 | - Fixed Readme 48 | ## 1.10.5 - 2020-06-12 49 | 50 | - Fixed 'overlayEntries.isEmpty': is not true 51 | 52 | ## [1.10.4] - 2020-15-05 53 | - [button] is now a [Widget] instead of [FlatButton] 54 | - Removed generic type requirement to extend Object 55 | - Fixed bar blur clipping 56 | 57 | ## [1.10.3] - 2020-15-05 58 | - Fixes example pictures 59 | 60 | ## [1.10.2] - 2020-15-05 61 | - Fixes SDK version 62 | 63 | ## [1.10.1] - 2020-07-05 64 | - With FLutter's 1.17 release, Flushbar 1.10 is now compatible with stable channel 65 | 66 | ## [1.10.0] - 2020-25-03 67 | - **Breaking change** fixes a breaking change introduced by Flutter. Only use this version if you are using flutter v1.15 or greater (currently on the beta channel) 68 | - **Breaking change** adds blockBackgroundInteraction property. 69 | - **Breaking change** overlayBlur renamed to routeBlur. Will be ignored if blockBackgroundInteraction is false 70 | - **Breaking change** overlayColor renamed to routeColor. Will be ignored if blockBackgroundInteraction is false 71 | - Now, if [showProgressIndicator] is true and [progressIndicatorController] is null, an infinite linear progress indicator will be shown 72 | - Performance improvements 73 | - Code refactoring 74 | 75 | ## [1.9.1] - 2019-21-10 76 | - Fixed shadows not showing up 77 | 78 | ## [1.9.0] - 2019-01-09 79 | - Added `maxWidth` property 80 | - Added `barBlur` which applies a BackdropFilter only to Flushbar's background 81 | - Default animation curve changed from `fastOutSlowIn` to `easeOutCirc` 82 | 83 | ## [1.8.2] - 2019-02-08 84 | - Blur overlay is now dismissible by click if `isDismissible == true` 85 | - Blur overlay will now animate until it disappears instead of vanishing 86 | 87 | ## [1.8.1] - 2019-29-07 88 | - Removed context requirement from flushbar_route 89 | - Fix onTap requiring a return value 90 | 91 | ## [1.8.0] - 2019-17-07 92 | - **Breaking Change** renamed `aroundPadding` to `margin` 93 | - Flushbar now supports uniform borders (same border on all sides) 94 | - Added `borderColor` property 95 | - Added `borderWidth` property 96 | - Added `padding` property - default still complies with material design specs 97 | 98 | ## [1.7.1+1] - 2019-10-07 99 | - Fixed environment variables 100 | 101 | ## [1.7.1] - 2019-10-07 102 | - Changed file docs to comply with dartdoc directives 103 | - Flutter minimum version for Flushbar is now 1.7.8 104 | - With Flutter version 1.7.8 hitting stable, there is no version restriction for stable channel users anymore 105 | 106 | ## [1.7.0] - 2019-05-06 107 | - add onTap property 108 | - fix exception caused by user dismissal while flushbar is appearing or hiding 109 | 110 | ## [1.6.0] - 2019-31-05 111 | - **breaking change** this fixes `The method 'detach' isn't defined for the class 'FocusScopeNode'` 112 | 113 | ## [1.5.3] - 2019-27-05 114 | - update README file 115 | 116 | ## [1.5.2] - 2019-26-05 117 | - `titleText` and `messageText` are now widgets so users can use `RichText` or `Text` 118 | - Add `shouldIconPulse` property 119 | 120 | ## [1.5.0] - 2019-04-05 121 | - **Breaking Change** boxShadow is now called boxShadows and is a List 122 | 123 | ## [1.4.0] - 2019-08-04 124 | - Add `overlayBlur` property that pushes an overlay blocking user input on the background. Only takes effect if greater then 0.0 125 | - Add `overlayColor` property that changes the overlay color. Default is transparent. Only takes effect if overlayBlur is greater then 0.0 126 | - Create new file for FlushbarRoute 127 | 128 | ## [1.3.1] - 2019-02-04 129 | - Constructor now has strongly typed parameters (my bad for forgetting it) 130 | - Improved null message error 131 | 132 | ## [1.3.0] - 2019-14-03 133 | - **Breaking Change** expect for `onStatusChanged`, all properties are now final. Two dot notation does 134 | not work anymore. Since you can only use the instance one time, this 135 | is the best practice. 136 | - Add `dismissDirection` property. 137 | - **Behaviour change** dismiss is now vertical by default. This is more natural since 138 | Flushbar show animation is also vertical. 139 | - It is now possible to dismiss a Flushbar that is not the top route. 140 | The only inconvenient is that it will not animate back (simply disappear) and the listener, if used, will not register the dismissal. 141 | - Updated README file 142 | 143 | ## [1.2.4] - 2019-05-03 144 | - Added FlushbarStyle.FLOATING & FlushbarStyle.GROUNDED 145 | - Fixed icon animation being started even if icon is null 146 | 147 | ## [1.2.3] - 2019-25-02 148 | - **Breaking Change** Flushbar now accepts a BoxShadow for a more customized shadow 149 | 150 | ## [1.2.2] - 2019-22-02 151 | - Fixed a bug when push an route after flushbar, and flushbar timer pop the current route out 152 | 153 | ## [1.2.1] - 2019-11-01 154 | - aroundPadding is now more flexible and receives EdgeInsets instead of an int 155 | 156 | ## [1.2.0] - 2018-09-12 157 | - add animationDuration argument. You can now control how long does it take to show and dismiss Flushbar 158 | 159 | ## [1.1.2] - 2018-24-10 160 | - icon argument can now be any widget, though I recommend using Icon or Image 161 | - added null checks 162 | 163 | ## [1.1.1] - 2018-17-10 164 | 165 | - Fixed bug where calling Navigator.push() on Flushbar swipe dismissal did not pop the route 166 | - Fixed bug where swipe to dismiss a padded Flushbar caused to being stuck at the edge 167 | 168 | ## [1.1.0] - 2018-11-10 169 | 170 | - Added two new features: aroundPadding and borderRadius 171 | - Fixed a bug where the overlay background was not null 172 | 173 | ## [1.0.1] - 2018-11-02 174 | 175 | - Texts now respond to alignment 176 | 177 | ## [1.0.0] - 2018-11-02 178 | 179 | - No changes. Simply reached stable after a month without new bugs 180 | 181 | ## [0.9.2] - 2018-09-29 182 | 183 | ### Changes 184 | 185 | - Dismissing a Flushbar that is not the top route no longer throws an exception 186 | - Dismissing a Flushbar that is not the top route has the following effects: 187 | * It does not animate back. It simply vanishes 188 | * FlushbarStatus listener will not register `FlushbarStatus.IS_HIDING` or `FlushbarStatus.DISMISSED` 189 | * It returns no value when the Future yield by `dismiss()` completes 190 | 191 | ### Fixes 192 | 193 | - Fixed an issue where a dismissible Flushbar would not cancel the timer and pop two routes instead of one 194 | 195 | ## [0.9.1] - 2018-09-25 196 | 197 | ### Changes 198 | 199 | - Fixed an issue where Flushbar could get stuck when swipe to dismiss was used 200 | - Minor layout tweeks 201 | - Flushbar gets a weird logo! Do not judge me. I'm not a designer :) 202 | - README file update 203 | - README file fixes 204 | 205 | ## [0.9.0] - 2018-09-10 206 | 207 | Looking good for version 1.0. Please, report any issues your have. 208 | 209 | ### Changes 210 | 211 | - **IMPORTANT** `dismiss()` now returns a future when the animation is completed and route is poped. That makes it easier to concatenate two or more Flushbars. 212 | - Major changes on how `show` and `dismiss` animations work, making Flushbar more reliable. 213 | - Trying to `dismiss()` a Flushbar that is not the top route is going to throw an error. 214 | - Pressing the back button will now properly `dismiss()` Flushbar. 215 | - Performance improvements. In and out animations are smoother. 216 | 217 | ### Layout Changes 218 | 219 | - Removed top padding when `flushbarPosition == FlushbarPosition.TOP` 220 | 221 | ## [0.8.3] - 2018-09-07 222 | 223 | ### Fixes 224 | 225 | - Fixed issue when `isDismissible` is set to false [Issue #6](https://github.com/AndreHaueisen/flushbar/issues/6#issue-357423067) 226 | - Fixed issue where the keyboard would hide Flushbar [Issue #7](https://github.com/AndreHaueisen/flushbar/issues/7#issue-357946307) 227 | 228 | ## [0.8.2] - 2018-08-27 229 | 230 | ### Changes 231 | 232 | - Add `key` property 233 | - Fixed bug here using flushbar_helper progressIndicator did not show 234 | - Fixed documentation about progressIndicator 235 | 236 | ## [0.8.1] - 2018-08-12 237 | 238 | ### Changes 239 | 240 | - Fixed Dart version issue 241 | 242 | ## [0.8.0] - 2018-08-11 243 | ### Breaking changes 244 | - Changed the behaviour of linearProgressIndicator to allow the user to controll its progress. See README.md for examples 245 | ### Changes 246 | - Added a left vertical bar to better convey the humor of the notification. See README.md for examples 247 | - Title is not mandatory anymore 248 | 249 | ## [0.7.6] - 2018-08-07 250 | ### Changes 251 | - Version update to supprt master channel 252 | 253 | ## [0.7.5] - 2018-07-28 254 | ### Changes 255 | - Fix bug where keyboard did not show when using a Form 256 | - Flushbar is now compatible with the master channel 257 | - Bug fixes 258 | 259 | ## [0.7.1] - 2018-07-08 260 | ### Changes 261 | - Flushbar doc update 262 | 263 | ## [0.7.0] - 2018-07-08 264 | ### Breaking changes 265 | - Flushbar does not need a global instance anymore 266 | - Flushbar it now made be used only one time. After it hits the dismissed state, that instance wont work anymore 267 | - Due to the behaviour above, there is no need to call commitChanges() anymore 268 | - Flushbar does not need to be within a Stack widget anymore 269 | - Purged state eliminated 270 | - FlushbarMorph is now called FlushbarHelper 271 | 272 | ### Changes 273 | - README.md is updated 274 | 275 | ### Known issues 276 | - When using a Form, the keyboard is not shown. Still figuring out how to solve it. 277 | 278 | ## [0.5.6] - 2018-06-20 279 | ### Changed 280 | - Fixed dependency issue 281 | 282 | ## [0.5.5] - 2018-06-20 283 | ### Changed 284 | - Updated flushbar_morph 285 | - Updated sdk version 286 | 287 | ## [0.5.4] - 2018-06-16 288 | ### Changed 289 | - Flushbar now animates size changes when commit is called while showing 290 | - Layout refinements 291 | 292 | ## [0.5.2] - 2018-06-05 293 | ### Changed 294 | - User input now receives a Form to facilitate field validation 295 | 296 | ## [0.5.1] - 2018-06-05 297 | ### Changed 298 | - Fixed brain fart. Same changes as 0.5.0 299 | 300 | ## [0.5.0] - 2018-06-05 301 | ### Changed 302 | - Removed change...() functions. Cascade notation is now recommended 303 | - Update readme file 304 | - Default message font size reduced from 16.0 to 14.0 305 | - Default title font size reduced from 16.0 to 15.0 306 | 307 | ## [0.4.7] - 2018-06-04 308 | ### Changed 309 | - Fixed bug with bar duration 310 | - Blink animation when Flushbar is not dismissed now animates the whole bar 311 | and is synchronised with content change. 312 | 313 | ## [0.4.5] - 2018-06-03 314 | ### Added 315 | - Blink animation when commitChanges() is called when Flushbar is not dismissed. This provides a 316 | smooth content transition 317 | - Helper class to morph Flushbar (FlushbarMorph) 318 | ### Changed 319 | - Code cleanup 320 | 321 | ## [0.4.0] - 2018-05-27 322 | ### Added 323 | - InputTextField 324 | 325 | ## [0.3.1] - 2018-05-27 326 | ### Changed 327 | - Fixed bar being automatically called 328 | - Title and message are not required at construction time 329 | - Better usage example 330 | - Removed callback from constructor 331 | 332 | ## [0.3.0] - 2018-05-27 333 | ### Changed 334 | - Removed the possibility to chose icon position 335 | - Widgets are now aligned correctly 336 | - Documentation improvements 337 | 338 | ## [0.2.5] - 2018-05-26 339 | ### Changed 340 | - Bug fixes 341 | - Moved icon animation into the flushbar 342 | - changeStatusListener() is now activated on change 343 | 344 | ## [0.2.0] - 2018-05-24 345 | ### Added 346 | - Removed requirement for a initial widget 347 | - OnStatusChanged callback so it is possible to listen to the various Flushbar status 348 | - The callback can be changed using changeStatusListener() 349 | - Started working on the README.md file 350 | 351 | ### Changed 352 | - IconAwareAnimation is now more general and it is called PulseAnimator 353 | - Flushbar now accepts an Icon instead of only the IconData and IconColor 354 | - Alignment changes 355 | - Default background color 356 | 357 | ## [0.0.1] - 2018-05-23 358 | 359 | ### Added 360 | - Flushbar creation 361 | - Single button action 362 | - Status listeners 363 | - Left or right icon positioning 364 | - Top or bottom positioning -------------------------------------------------------------------------------- /lib/flushbar_route.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:ui'; 3 | 4 | import 'package:flutter/material.dart'; 5 | 6 | import 'flushbar.dart'; 7 | 8 | class FlushbarRoute extends OverlayRoute { 9 | final Flushbar flushbar; 10 | final Builder _builder; 11 | final Completer _transitionCompleter = Completer(); 12 | final FlushbarStatusCallback? _onStatusChanged; 13 | 14 | Animation? _filterBlurAnimation; 15 | Animation? _filterColorAnimation; 16 | Alignment? _initialAlignment; 17 | Alignment? _endAlignment; 18 | bool _wasDismissedBySwipe = false; 19 | Timer? _timer; 20 | T? _result; 21 | FlushbarStatus? currentStatus; 22 | 23 | FlushbarRoute({ 24 | required this.flushbar, 25 | RouteSettings? settings, 26 | }) : _builder = Builder(builder: (BuildContext innerContext) { 27 | return GestureDetector( 28 | onTap: 29 | flushbar.onTap != null ? () => flushbar.onTap!(flushbar) : null, 30 | child: flushbar, 31 | ); 32 | }), 33 | _onStatusChanged = flushbar.onStatusChanged, 34 | super(settings: settings) { 35 | _configureAlignment(flushbar.flushbarPosition); 36 | } 37 | 38 | void _configureAlignment(FlushbarPosition flushbarPosition) { 39 | switch (flushbar.flushbarPosition) { 40 | case FlushbarPosition.TOP: 41 | { 42 | _initialAlignment = const Alignment(-1.0, -2.0); 43 | _endAlignment = flushbar.endOffset != null 44 | ? const Alignment(-1.0, -1.0) + 45 | Alignment(flushbar.endOffset!.dx, flushbar.endOffset!.dy) 46 | : const Alignment(-1.0, -1.0); 47 | break; 48 | } 49 | case FlushbarPosition.BOTTOM: 50 | { 51 | _initialAlignment = const Alignment(-1.0, 2.0); 52 | _endAlignment = flushbar.endOffset != null 53 | ? const Alignment(-1.0, 1.0) + 54 | Alignment(flushbar.endOffset!.dx, flushbar.endOffset!.dy) 55 | : const Alignment(-1.0, 1.0); 56 | break; 57 | } 58 | } 59 | } 60 | 61 | Future get completed => _transitionCompleter.future; 62 | bool get opaque => false; 63 | 64 | @override 65 | Future willPop() { 66 | if (!flushbar.isDismissible) { 67 | return Future.value(RoutePopDisposition.doNotPop); 68 | } 69 | 70 | return Future.value(RoutePopDisposition.pop); 71 | } 72 | 73 | @override 74 | Iterable createOverlayEntries() { 75 | final overlays = []; 76 | 77 | if (flushbar.blockBackgroundInteraction) { 78 | overlays.add( 79 | OverlayEntry( 80 | builder: (BuildContext context) { 81 | return Listener( 82 | onPointerDown: 83 | flushbar.isDismissible ? (_) => flushbar.dismiss() : null, 84 | child: _createBackgroundOverlay(), 85 | ); 86 | }, 87 | maintainState: false, 88 | opaque: opaque), 89 | ); 90 | } 91 | 92 | overlays.add( 93 | OverlayEntry( 94 | builder: (BuildContext context) { 95 | final Widget annotatedChild = Semantics( 96 | focused: false, 97 | container: true, 98 | explicitChildNodes: true, 99 | child: AlignTransition( 100 | alignment: _animation!, 101 | child: flushbar.isDismissible 102 | ? _getDismissibleFlushbar(_builder) 103 | : _getFlushbar(), 104 | ), 105 | ); 106 | return annotatedChild; 107 | }, 108 | maintainState: false, 109 | opaque: opaque), 110 | ); 111 | 112 | return overlays; 113 | } 114 | 115 | Widget _createBackgroundOverlay() { 116 | if (_filterBlurAnimation != null && _filterColorAnimation != null) { 117 | return AnimatedBuilder( 118 | animation: _filterBlurAnimation!, 119 | builder: (context, child) { 120 | return BackdropFilter( 121 | filter: ImageFilter.blur( 122 | sigmaX: _filterBlurAnimation!.value, 123 | sigmaY: _filterBlurAnimation!.value), 124 | child: Container( 125 | constraints: const BoxConstraints.expand(), 126 | color: _filterColorAnimation!.value, 127 | ), 128 | ); 129 | }, 130 | ); 131 | } 132 | 133 | if (_filterBlurAnimation != null) { 134 | return AnimatedBuilder( 135 | animation: _filterBlurAnimation!, 136 | builder: (context, child) { 137 | return BackdropFilter( 138 | filter: ImageFilter.blur( 139 | sigmaX: _filterBlurAnimation!.value, 140 | sigmaY: _filterBlurAnimation!.value), 141 | child: Container( 142 | constraints: const BoxConstraints.expand(), 143 | color: Colors.transparent, 144 | ), 145 | ); 146 | }, 147 | ); 148 | } 149 | 150 | if (_filterColorAnimation != null) { 151 | AnimatedBuilder( 152 | animation: _filterColorAnimation!, 153 | builder: (context, child) { 154 | return Container( 155 | constraints: const BoxConstraints.expand(), 156 | color: _filterColorAnimation!.value, 157 | ); 158 | }, 159 | ); 160 | } 161 | 162 | return Container( 163 | constraints: const BoxConstraints.expand(), 164 | color: Colors.transparent, 165 | ); 166 | } 167 | 168 | /// This string is a workaround until Dismissible supports a returning item 169 | String dismissibleKeyGen = ''; 170 | 171 | Widget _getDismissibleFlushbar(Widget child) { 172 | return Dismissible( 173 | direction: _getDismissDirection(), 174 | resizeDuration: null, 175 | confirmDismiss: (_) { 176 | if (currentStatus == FlushbarStatus.IS_APPEARING || 177 | currentStatus == FlushbarStatus.IS_HIDING) { 178 | return Future.value(false); 179 | } 180 | return Future.value(true); 181 | }, 182 | key: Key(dismissibleKeyGen), 183 | onDismissed: (_) { 184 | dismissibleKeyGen += '1'; 185 | _cancelTimer(); 186 | _wasDismissedBySwipe = true; 187 | 188 | if (isCurrent) { 189 | navigator!.pop(); 190 | } else { 191 | navigator!.removeRoute(this); 192 | } 193 | }, 194 | child: _getFlushbar(), 195 | ); 196 | } 197 | 198 | DismissDirection _getDismissDirection() { 199 | if (flushbar.dismissDirection == FlushbarDismissDirection.HORIZONTAL) { 200 | return DismissDirection.horizontal; 201 | } else { 202 | if (flushbar.flushbarPosition == FlushbarPosition.TOP) { 203 | return DismissDirection.up; 204 | } else { 205 | return DismissDirection.down; 206 | } 207 | } 208 | } 209 | 210 | Widget _getFlushbar() { 211 | return Container( 212 | margin: flushbar.margin, 213 | child: _builder, 214 | ); 215 | } 216 | 217 | @override 218 | bool get finishedWhenPopped => 219 | _controller!.status == AnimationStatus.dismissed; 220 | 221 | /// The animation that drives the route's transition and the previous route's 222 | /// forward transition. 223 | Animation? get animation => _animation; 224 | Animation? _animation; 225 | 226 | /// The animation controller that the route uses to drive the transitions. 227 | /// 228 | /// The animation itself is exposed by the [animation] property. 229 | @protected 230 | AnimationController? get controller => _controller; 231 | AnimationController? _controller; 232 | 233 | /// Called to create the animation controller that will drive the transitions to 234 | /// this route from the previous one, and back to the previous route from this 235 | /// one. 236 | AnimationController createAnimationController() { 237 | assert(!_transitionCompleter.isCompleted, 238 | 'Cannot reuse a $runtimeType after disposing it.'); 239 | assert(flushbar.animationDuration >= Duration.zero); 240 | return AnimationController( 241 | duration: flushbar.animationDuration, 242 | debugLabel: debugLabel, 243 | vsync: navigator!, 244 | ); 245 | } 246 | 247 | /// Called to create the animation that exposes the current progress of 248 | /// the transition controlled by the animation controller created by 249 | /// [createAnimationController()]. 250 | Animation createAnimation() { 251 | assert(!_transitionCompleter.isCompleted, 252 | 'Cannot reuse a $runtimeType after disposing it.'); 253 | assert(_controller != null); 254 | return AlignmentTween(begin: _initialAlignment, end: _endAlignment).animate( 255 | CurvedAnimation( 256 | parent: _controller!, 257 | curve: flushbar.forwardAnimationCurve, 258 | reverseCurve: flushbar.reverseAnimationCurve, 259 | ), 260 | ); 261 | } 262 | 263 | Animation? createBlurFilterAnimation() { 264 | if (flushbar.routeBlur == null) return null; 265 | 266 | return Tween(begin: 0.0, end: flushbar.routeBlur).animate( 267 | CurvedAnimation( 268 | parent: _controller!, 269 | curve: const Interval( 270 | 0.0, 271 | 0.35, 272 | curve: Curves.easeInOutCirc, 273 | ), 274 | ), 275 | ); 276 | } 277 | 278 | Animation? createColorFilterAnimation() { 279 | if (flushbar.routeColor == null) return null; 280 | 281 | return ColorTween(begin: Colors.transparent, end: flushbar.routeColor) 282 | .animate( 283 | CurvedAnimation( 284 | parent: _controller!, 285 | curve: const Interval( 286 | 0.0, 287 | 0.35, 288 | curve: Curves.easeInOutCirc, 289 | ), 290 | ), 291 | ); 292 | } 293 | 294 | //copy of `routes.dart` 295 | void _handleStatusChanged(AnimationStatus status) { 296 | switch (status) { 297 | case AnimationStatus.completed: 298 | currentStatus = FlushbarStatus.SHOWING; 299 | if (_onStatusChanged != null) _onStatusChanged!(currentStatus); 300 | if (overlayEntries.isNotEmpty) overlayEntries.first.opaque = opaque; 301 | 302 | break; 303 | case AnimationStatus.forward: 304 | currentStatus = FlushbarStatus.IS_APPEARING; 305 | if (_onStatusChanged != null) _onStatusChanged!(currentStatus); 306 | break; 307 | case AnimationStatus.reverse: 308 | currentStatus = FlushbarStatus.IS_HIDING; 309 | if (_onStatusChanged != null) _onStatusChanged!(currentStatus); 310 | if (overlayEntries.isNotEmpty) overlayEntries.first.opaque = false; 311 | break; 312 | case AnimationStatus.dismissed: 313 | assert(!overlayEntries.first.opaque); 314 | // We might still be the current route if a subclass is controlling the 315 | // the transition and hits the dismissed status. For example, the iOS 316 | // back gesture drives this animation to the dismissed status before 317 | // popping the navigator. 318 | currentStatus = FlushbarStatus.DISMISSED; 319 | if (_onStatusChanged != null) _onStatusChanged!(currentStatus); 320 | 321 | if (!isCurrent) { 322 | navigator!.finalizeRoute(this); 323 | if (overlayEntries.isNotEmpty) { 324 | overlayEntries.clear(); 325 | } 326 | assert(overlayEntries.isEmpty); 327 | } 328 | break; 329 | } 330 | changedInternalState(); 331 | } 332 | 333 | @override 334 | void install() { 335 | assert(!_transitionCompleter.isCompleted, 336 | 'Cannot install a $runtimeType after disposing it.'); 337 | _controller = createAnimationController(); 338 | assert(_controller != null, 339 | '$runtimeType.createAnimationController() returned null.'); 340 | _filterBlurAnimation = createBlurFilterAnimation(); 341 | _filterColorAnimation = createColorFilterAnimation(); 342 | _animation = createAnimation(); 343 | assert(_animation != null, '$runtimeType.createAnimation() returned null.'); 344 | super.install(); 345 | } 346 | 347 | @override 348 | TickerFuture didPush() { 349 | assert(_controller != null, 350 | '$runtimeType.didPush called before calling install() or after calling dispose().'); 351 | assert(!_transitionCompleter.isCompleted, 352 | 'Cannot reuse a $runtimeType after disposing it.'); 353 | _animation!.addStatusListener(_handleStatusChanged); 354 | _configureTimer(); 355 | super.didPush(); 356 | return _controller!.forward(); 357 | } 358 | 359 | @override 360 | void didReplace(Route? oldRoute) { 361 | assert(_controller != null, 362 | '$runtimeType.didReplace called before calling install() or after calling dispose().'); 363 | assert(!_transitionCompleter.isCompleted, 364 | 'Cannot reuse a $runtimeType after disposing it.'); 365 | if (oldRoute is FlushbarRoute) { 366 | _controller!.value = oldRoute._controller!.value; 367 | } 368 | _animation!.addStatusListener(_handleStatusChanged); 369 | super.didReplace(oldRoute); 370 | } 371 | 372 | @override 373 | bool didPop(T? result) { 374 | assert(_controller != null, 375 | '$runtimeType.didPop called before calling install() or after calling dispose().'); 376 | assert(!_transitionCompleter.isCompleted, 377 | 'Cannot reuse a $runtimeType after disposing it.'); 378 | 379 | _result = result; 380 | _cancelTimer(); 381 | 382 | if (_wasDismissedBySwipe) { 383 | Timer(const Duration(milliseconds: 200), () { 384 | _controller!.reset(); 385 | }); 386 | 387 | _wasDismissedBySwipe = false; 388 | } else { 389 | _controller!.reverse(); 390 | } 391 | 392 | return super.didPop(result); 393 | } 394 | 395 | void _configureTimer() { 396 | if (flushbar.duration != null) { 397 | if (_timer != null && _timer!.isActive) { 398 | _timer!.cancel(); 399 | } 400 | _timer = Timer(flushbar.duration!, () { 401 | if (isCurrent) { 402 | navigator!.pop(); 403 | } else if (isActive) { 404 | navigator!.removeRoute(this); 405 | } 406 | }); 407 | } else { 408 | if (_timer != null) { 409 | _timer!.cancel(); 410 | } 411 | } 412 | } 413 | 414 | void _cancelTimer() { 415 | if (_timer != null && _timer!.isActive) { 416 | _timer!.cancel(); 417 | } 418 | } 419 | 420 | /// Whether this route can perform a transition to the given route. 421 | /// 422 | /// Subclasses can override this method to restrict the set of routes they 423 | /// need to coordinate transitions with. 424 | bool canTransitionTo(FlushbarRoute nextRoute) => true; 425 | 426 | /// Whether this route can perform a transition from the given route. 427 | /// 428 | /// Subclasses can override this method to restrict the set of routes they 429 | /// need to coordinate transitions with. 430 | bool canTransitionFrom(FlushbarRoute previousRoute) => true; 431 | 432 | @override 433 | void dispose() { 434 | assert(!_transitionCompleter.isCompleted, 435 | 'Cannot dispose a $runtimeType twice.'); 436 | _controller?.dispose(); 437 | _transitionCompleter.complete(_result); 438 | super.dispose(); 439 | } 440 | 441 | /// A short description of this route useful for debugging. 442 | String get debugLabel => '$runtimeType'; 443 | 444 | @override 445 | String toString() => '$runtimeType(animation: $_controller)'; 446 | } 447 | 448 | FlushbarRoute showFlushbar( 449 | {required BuildContext context, required Flushbar flushbar}) { 450 | return FlushbarRoute( 451 | flushbar: flushbar, 452 | settings: const RouteSettings(name: FLUSHBAR_ROUTE_NAME), 453 | ); 454 | } 455 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # another_flushbar 2 | 3 | Use this package if you need more customization when notifying your user. For Android developers, it is made to substitute 4 | toasts and snackbars. IOS developers, I don't know what you use there, but you will like it. 5 | 6 | See the [install instructions](https://pub.dev/packages/another_flushbar/install). 7 | 8 | ## Quick reference 9 | 10 | Since customization requires a lot of properties, here is a quick cheatsheet: 11 | 12 | Property | What does it do 13 | -------- | --------------- 14 | title | The title displayed to the user 15 | titleColor | The title color displayed to the user 16 | titleSize | The title size displayed to the user 17 | message | The message displayed to the user. 18 | messageColor | The message color displayed to the user. 19 | messageSize | The message size displayed to the user. 20 | titleText | Replaces [title]. Although this accepts a [widget], **it is meant to receive [Text] or [RichText]** 21 | messageText | Replaces [message]. Although this accepts a [widget], **it is meant to receive [Text] or [RichText]** 22 | icon | You can use any widget here, but I recommend [Icon] or [Image] as indication of what kind of message you are displaying. Other widgets may break the layout 23 | shouldIconPulse | An option to animate the icon (if present). Defaults to true. 24 | maxWidth | Used to limit Flushbar width (usually on large screens) 25 | margin | Adds a custom margin to Flushbar 26 | padding | Adds a custom padding to Flushbar. The default follows material design guide line 27 | borderRadius | Adds a radius to specified corners of Flushbar. Best combined with [margin]. I do not recommend using it with [showProgressIndicator] or [leftBarIndicatorColor] 28 | textDirection | [TextDirection.ltr] by default. [Directionality.of(context)] to know whether it would be [TextDirection.ltr] or [TextDirection.rtl] 29 | borderColor | Adds a border to every side of Flushbar. I do not recommend using it with [showProgressIndicator] or [leftBarIndicatorColor] 30 | borderWidth | Changes the width of the border if [borderColor] is specified 31 | backgroundColor | Flushbar background color. Will be ignored if [backgroundGradient] is not null. 32 | leftBarIndicatorColor | If not null, shows a left vertical bar to better indicate the humor of the notification. It is not possible to use it with a [Form] and I do not recommend using it with [LinearProgressIndicator]. 33 | boxShadows | The shadows generated by Flushbar. Leave it null if you don't want a shadow. You can use more than one if you feel the need. Check [this example](https://github.com/flutter/flutter/blob/main/packages/flutter/lib/src/material/shadows.dart) 34 | backgroundGradient | Flushbar background gradient. Makes [backgroundColor] be ignored. 35 | mainButton | Use if you need an action from the user. [FlatButton] is recommended here. 36 | onTap | A callback that registers the user's click anywhere. An alternative to [mainButton] 37 | duration | How long until Flushbar will hide itself (be dismissed). To make it indefinite, leave it null. 38 | isDismissible | Determines if the user can swipe or click the overlay (if [routeBlur] > 0) to dismiss. It is recommended that you set [duration] != null if this is false. If the user swipes to dismiss or clicks the overlay, no value will be returned. 39 | dismissDirection | FlushbarDismissDirection.VERTICAL by default. Can also be [FlushbarDismissDirection.HORIZONTAL] in which case both left and right dismiss are allowed. 40 | flushbarPosition | Flushbar can be based on [FlushbarPosition.TOP] or on [FlushbarPosition.BOTTOM] of your screen. [FlushbarPosition.BOTTOM] is the default. 41 | flushbarStyle | Flushbar can be floating or be grounded to the edge of the screen. If grounded, I do not recommend using [margin] or [borderRadius]. [FlushbarStyle.FLOATING] is the default 42 | forwardAnimationCurve | The [Curve] animation used when show() is called. [Curves.easeOut] is default. 43 | reverseAnimationCurve | The [Curve] animation used when dismiss() is called. [Curves.fastOutSlowIn] is default. 44 | animationDuration | Use it to speed up or slow down the animation duration 45 | showProgressIndicator | true if you want to show a [LinearProgressIndicator]. If [progressIndicatorController] is null, an infinite progress indicator will be shown 46 | progressIndicatorController | An optional [AnimationController] when you want to control the progress of your [LinearProgressIndicator]. You are responsible for controlling the progress 47 | progressIndicatorBackgroundColor | a [LinearProgressIndicator] configuration parameter. 48 | progressIndicatorValueColor | a [LinearProgressIndicator] configuration parameter. 49 | barBlur | Default is 0.0. If different than 0.0, blurs only Flushbar's background. To take effect, make sure your [backgroundColor] has some opacity. The greater the value, the greater the blur. 50 | blockBackgroundInteraction | Determines if user can interact with the screen behind it. If this is false, [routeBlur] and [routeColor] will be ignored 51 | routeBlur | Default is 0.0. If different than 0.0, creates a blurred overlay that prevents the user from interacting with the screen. The greater the value, the greater the blur. It does not take effect if [blockBackgroundInteraction] is false 52 | routeColor | Default is [Colors.transparent]. Only takes effect if [routeBlur] > 0.0. Make sure you use a color with transparency e.g. `Colors.grey[600].withOpacity(0.2)`. It does not take effect if [blockBackgroundInteraction] is false 53 | userInputForm | A [TextFormField] in case you want a simple user input. Every other widget is ignored if this is not null. 54 | onStatusChanged | a callback for you to listen to the different Flushbar status 55 | 56 | #### Quick tip 57 | 58 | If you use a lot of those properties, it makes sense to make a factory to help with your Flushbar's base appearance. 59 | Things like shadows, padding, margins, text styles usually don't change within the app. Take a look at FlushbarHelper class and use it as an example. 60 | 61 | ## We are on YouTube! 62 | 63 | While studying Flutter I stumbled on two amazing tutorials on how to use Flushbar. 64 | Make sure you show those guys some love. 65 | 1. A beginners [tutorial](https://www.youtube.com/watch?v=KNpxyyA8MDA) by **Matej Rešetár** 66 | 2. A more [advanced usage](https://www.youtube.com/watch?v=FRCvqkyeCzQ) by **Javier González Rodríguez** 67 | 68 | ## Getting Started 69 | 70 | The examples bellow were updated for version 1.3.0. Changes might have been made. See the [changelog](CHANGELOG.md) if any of the examples do not 71 | reflect Flushbar's current state. 72 | 73 | ### The possibilities 74 | 75 | ![Flushbar Animated](https://github.com/cmdrootaccess/another-flushbar/raw/main/readme_resources/flushbar_animated.gif) 76 | 77 | ### A basic Flushbar 78 | 79 | The most basic Flushbar uses only a message. Failing to provide it before you call `show()` will result in a runtime error. 80 | `Duration`, if not provided, will create an infinite Flushbar, only dismissible by code, back button clicks, or a drag (case `isDismissible` is set to `true`). 81 | 82 | - Note that only `message` is a required parameter. All the other ones are optional 83 | 84 | ```dart 85 | class YourAwesomeApp extends StatelessWidget { 86 | 87 | @override 88 | Widget build(BuildContext context) { 89 | return MaterialApp( 90 | title: 'YourAwesomeApp', 91 | home: Scaffold( 92 | Container( 93 | child: Center( 94 | child: MaterialButton( 95 | onPressed: (){ 96 | Flushbar( 97 | title: "Hey Ninja", 98 | message: "Lorem Ipsum is simply dummy text of the printing and typesetting industry", 99 | duration: Duration(seconds: 3), 100 | )..show(context); 101 | }, 102 | ), 103 | ), 104 | ), 105 | ), 106 | ); 107 | } 108 | } 109 | ``` 110 | 111 | ![Basic Example](https://github.com/cmdrootaccess/another-flushbar/raw/main/readme_resources/basic_bar.png) 112 | 113 | ### Lets get crazy Flushbar 114 | 115 | Here is how customized things can get. 116 | 117 | ```dart 118 | Flushbar( 119 | title: "Hey Ninja", 120 | titleColor: Colors.white, 121 | message: "Lorem Ipsum is simply dummy text of the printing and typesetting industry", 122 | flushbarPosition: FlushbarPosition.TOP, 123 | flushbarStyle: FlushbarStyle.FLOATING, 124 | reverseAnimationCurve: Curves.decelerate, 125 | forwardAnimationCurve: Curves.elasticOut, 126 | backgroundColor: Colors.red, 127 | boxShadows: [BoxShadow(color: Colors.blue[800], offset: Offset(0.0, 2.0), blurRadius: 3.0)], 128 | backgroundGradient: LinearGradient(colors: [Colors.blueGrey, Colors.black]), 129 | isDismissible: false, 130 | duration: Duration(seconds: 4), 131 | icon: Icon( 132 | Icons.check, 133 | color: Colors.greenAccent, 134 | ), 135 | mainButton: FlatButton( 136 | onPressed: () {}, 137 | child: Text( 138 | "CLAP", 139 | style: TextStyle(color: Colors.amber), 140 | ), 141 | ), 142 | showProgressIndicator: true, 143 | progressIndicatorBackgroundColor: Colors.blueGrey, 144 | titleText: Text( 145 | "Hello Hero", 146 | style: TextStyle( 147 | fontWeight: FontWeight.bold, fontSize: 20.0, color: Colors.yellow[600], fontFamily: "ShadowsIntoLightTwo"), 148 | ), 149 | messageText: Text( 150 | "You killed that giant monster in the city. Congratulations!", 151 | style: TextStyle(fontSize: 18.0, color: Colors.green, fontFamily: "ShadowsIntoLightTwo"), 152 | ), 153 | ); 154 | ``` 155 | 156 | ![Complete Example](https://github.com/cmdrootaccess/another-flushbar/raw/main/readme_resources/complete_bar.png) 157 | 158 | - Don't forget to call `show()` or the bar will stay hidden. 159 | - To deactivate any of those properties, pass `null` to it. 160 | 161 | ### Styles 162 | Flushbar can be either floating or grounded to the edge of the screen. 163 | I don't recommend using `margin` or `borderRadius` if you chose `FlushbarStyle.GROUNDED` style. 164 | 165 | ```dart 166 | Flushbar(flushbarStyle: FlushbarStyle.FLOATING) 167 | ``` 168 | or 169 | ```dart 170 | Flushbar(flushbarStyle: FlushbarStyle.GROUNDED) 171 | ``` 172 | Floating Style | Grounded Style 173 | :------------------------------------------------------:|:-------------------------------------------------------: 174 | ![Floating Style](https://github.com/cmdrootaccess/another-flushbar/raw/main/readme_resources/floating_style.png) | ![Grounded Style](readme_resources/grounded_style.png) 175 | 176 | ### Padding and Border Radius 177 | You can give it some padding and a border radius. Works best with `FlushbarStyle.FLOATING` 178 | 179 | ```dart 180 | Flushbar( 181 | margin: EdgeInsets.all(8), 182 | borderRadius: BorderRadius.circular(8), 183 | ); 184 | 185 | ``` 186 | ![Padding and Radius](https://github.com/cmdrootaccess/another-flushbar/raw/main/readme_resources/padding_and_radius.png) 187 | 188 | ### Left indicator bar 189 | 190 | Flushbar has a lateral bar to better convey the humor of the notification. To use it, simple give `leftBarIndicatorColor` a color. 191 | 192 | ```dart 193 | Flushbar( 194 | message: "Lorem Ipsum is simply dummy text of the printing and typesetting industry", 195 | icon: Icon( 196 | Icons.info_outline, 197 | size: 28.0, 198 | color: Colors.blue[300], 199 | ), 200 | duration: Duration(seconds: 3), 201 | leftBarIndicatorColor: Colors.blue[300], 202 | )..show(context); 203 | ``` 204 | 205 | ![Left indicator example](https://github.com/cmdrootaccess/another-flushbar/raw/main/readme_resources/left_bar_indicator.png) 206 | 207 | ### Customize your text 208 | 209 | If you need a more fancy text, you can use [Text](https://docs.flutter.io/flutter/widgets/Text-class.html) or [RichText](https://api.flutter.dev/flutter/widgets/RichText-class.html) 210 | and pass it to the `titleText` or `messageText` variables. 211 | 212 | - Note that `title` will be ignored if `titleText` is not `null` 213 | - Note that `message` will be ignored if `messageText` is not `null` 214 | 215 | ```dart 216 | Flushbar( 217 | title: "Hey Ninja", //ignored since titleText != null 218 | message: "Lorem Ipsum is simply dummy text of the printing and typesetting industry", //ignored since messageText != null 219 | titleText: Text("Hello Hero", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20.0 color: Colors.yellow[600], fontFamily:"ShadowsIntoLightTwo"),), 220 | messageText: Text("You killed that giant monster in the city. Congratulations!", style: TextStyle(fontSize: 16.0, color: Colors.green[fontFamily: "ShadowsIntoLightTwo"),), 221 | )..show(context); 222 | ``` 223 | 224 | ![Customized Text](https://github.com/cmdrootaccess/another-flushbar/raw/main/readme_resources/text_bar.png) 225 | 226 | ### Customize background and shadow 227 | 228 | You can paint the background with any color you want. You can use any shadow you want. 229 | Just give it a `backgroundColor` and `boxShadows`. 230 | 231 | ```dart 232 | Flushbar( 233 | title: "Hey Ninja", 234 | message: "Lorem Ipsum is simply dummy text of the printing and typesetting industry", 235 | backgroundColor: Colors.red, 236 | boxShadows: [BoxShadow(color: Colors.red[800], offset: Offset(0.0, 2.0), blurRadius: 3.0,)], 237 | )..show(context); 238 | ``` 239 | 240 | ![Background and Shadow](https://github.com/cmdrootaccess/another-flushbar/raw/main/readme_resources/background_color_bar.png) 241 | 242 | Want a gradient in the background? No problem. 243 | 244 | - Note that `backgroundColor` will be ignored while `backgroundGradient` is not `null` 245 | 246 | ```dart 247 | Flushbar( 248 | title: "Hey Ninja", 249 | message: "Lorem Ipsum is simply dummy text of the printing and typesetting industry", 250 | backgroundGradient: LinearGradient(colors: [Colors.blue, Colors.teal]), 251 | backgroundColor: Colors.red, 252 | boxShadows: [BoxShadow(color: Colors.blue[800], offset: Offset(0.0, 2.0), blurRadius: 3.0,)], 253 | )..show(context); 254 | ``` 255 | 256 | ![Background Gradient](https://github.com/cmdrootaccess/another-flushbar/raw/main/readme_resources/gradient_bar.png) 257 | 258 | ### Icon and button action 259 | 260 | Let us put a Icon that has a `PulseAnimation`. Icons have this animation by default and cannot be changed as of now. 261 | Also, let us put a button. Have you noticed that `show()` returns a `Future`? 262 | This Future will yield a value when you call `dismiss([T result])`. 263 | I recommend that you specify the `result` generic type if you intend to collect an user input. 264 | 265 | ```dart 266 | Flushbar flush; 267 | bool _wasButtonClicked; 268 | ``` 269 | 270 | ```dart 271 | @override 272 | Widget build(BuildContext context) { 273 | return Container( 274 | child: Center( 275 | child: MaterialButton( 276 | onPressed: () { 277 | flush = Flushbar( 278 | title: "Hey Ninja", 279 | message: "Lorem Ipsum is simply dummy text of the printing and typesetting industry", 280 | icon: Icon( 281 | Icons.info_outline, 282 | color: Colors.blue,), 283 | mainButton: FlatButton( 284 | onPressed: () { 285 | flush.dismiss(true); // result = true 286 | }, 287 | child: Text( 288 | "ADD", 289 | style: TextStyle(color: Colors.amber), 290 | ), 291 | ),) // is the type of the result passed to dismiss() and collected by show().then((result){}) 292 | ..show(context).then((result) { 293 | setState(() { // setState() is optional here 294 | _wasButtonClicked = result; 295 | }); 296 | }); 297 | }, 298 | ), 299 | ), 300 | ); 301 | } 302 | ``` 303 | 304 | ![Icon and Button](https://github.com/cmdrootaccess/another-flushbar/raw/main/readme_resources/icon_and_button_bar.png) 305 | 306 | ### Flushbar position 307 | 308 | Flushbar can be at `FlushbarPosition.BOTTOM` or `FlushbarPosition.TOP`. 309 | 310 | ```dart 311 | Flushbar( 312 | flushbarPosition: FlushbarPosition.TOP, 313 | title: "Hey Ninja", 314 | message: "Lorem Ipsum is simply dummy text of the printing and typesetting industry",)..show(context); 315 | ``` 316 | 317 | ![Bar position](https://github.com/cmdrootaccess/another-flushbar/raw/main/readme_resources/position_bar.png) 318 | 319 | ### Duration and dismiss policy 320 | 321 | By default, Flushbar is infinite. To set a duration, use the `duration` property. 322 | By default, Flushbar is dismissible by the user. A right or left drag will dismiss it. 323 | Set `isDismissible` to `false` to change this behaviour. 324 | 325 | ```dart 326 | Flushbar( 327 | title: "Hey Ninja", 328 | message: "Lorem Ipsum is simply dummy text of the printing and typesetting industry", 329 | duration: Duration(seconds: 3), 330 | isDismissible: false, 331 | )..show(context); 332 | ``` 333 | 334 | ### Progress Indicator 335 | 336 | If you are loading something, use a [LinearProgressIndicator](https://docs.flutter.io/flutter/material/LinearProgressIndicator-class.html) 337 | If you want an undetermined progress indicator, do not set `progressIndicatorController`. 338 | If you want a determined progress indicator, you now have full control over the progress since you own the `AnimationController` 339 | 340 | - There is no need to add a listener to your controller just to call `setState(){}`. Once you pass in your controller, `Flushbar` will do this automatically. Just make sure you call `_controller.forward()` 341 | 342 | ```dart 343 | 344 | AnimationController _controller = AnimationController( 345 | vsync: this, 346 | duration: Duration(seconds: 3), 347 | ); 348 | 349 | Flushbar( 350 | title: "Hey Ninja", 351 | message: "Lorem Ipsum is simply dummy text of the printing and typesetting industry", 352 | showProgressIndicator: true, 353 | progressIndicatorController: _controller, 354 | progressIndicatorBackgroundColor: Colors.grey[800], 355 | )..show(context); 356 | ``` 357 | 358 | ### Show and dismiss animation curves 359 | 360 | You can set custom animation curves using `forwardAnimationCurve` and `reverseAnimationCurve`. 361 | 362 | ```dart 363 | Flushbar( 364 | forwardAnimationCurve: Curves.decelerate, 365 | reverseAnimationCurve: Curves.easeOut, 366 | title: "Hey Ninja", 367 | message: "Lorem Ipsum is simply dummy text of the printing and typesetting industry", 368 | )..show(context); 369 | ``` 370 | 371 | ### Listen to status updates 372 | 373 | You can listen to status update using the `onStatusChanged` property. 374 | 375 | - Note that when you pass a new listener using `onStatusChanged`, it will activate once immediately so you can check in what state the Flushbar is. 376 | 377 | ```dart 378 | 379 | Flushbar flushbar = Flushbar(title: "Hey Ninja", message: "Lorem Ipsum is simply dummy text of the printing and typesetting industry"); 380 | 381 | flushbar 382 | ..onStatusChanged = (FlushbarStatus status) { 383 | switch (status) { 384 | case FlushbarStatus.SHOWING: 385 | { 386 | doSomething(); 387 | break; 388 | } 389 | case FlushbarStatus.IS_APPEARING: 390 | { 391 | doSomethingElse(); 392 | break; 393 | } 394 | case FlushbarStatus.IS_HIDING: 395 | { 396 | doSomethingElse(); 397 | break; 398 | } 399 | case FlushbarStatus.DISMISSED: 400 | { 401 | doSomethingElse(); 402 | break; 403 | } 404 | } 405 | } 406 | ..show(context); 407 | 408 | ``` 409 | 410 | ### Input text 411 | 412 | Sometimes we just want a simple user input. Use the property`userInputForm`. 413 | 414 | - Note that buttons, messages, and icons will be ignored if `userInputForm != null` 415 | - `dismiss(result)` will yield result. `dismiss()` will yield null. 416 | 417 | ```dart 418 | Flushbar> flush; 419 | final GlobalKey _formKey = GlobalKey(); 420 | ``` 421 | 422 | ```dart 423 | TextFormField getFormField(String text) { 424 | return TextFormField( 425 | initialValue: text, 426 | style: TextStyle(color: Colors.white), 427 | maxLength: 100, 428 | maxLines: 1, 429 | maxLengthEnforced: true, 430 | decoration: InputDecoration( 431 | fillColor: Colors.white10, 432 | filled: true, 433 | icon: Icon( 434 | Icons.label, 435 | color: Colors.grey[500], 436 | ), 437 | border: UnderlineInputBorder(), 438 | helperText: "Helper Text", 439 | helperStyle: TextStyle(color: Colors.grey), 440 | labelText: "Label Text", 441 | labelStyle: TextStyle(color: Colors.grey)), 442 | ); 443 | } 444 | 445 | flush = Flushbar>( 446 | userInputForm = Form( 447 | key: _formKey, 448 | child: Column( 449 | mainAxisSize: MainAxisSize.min, 450 | children: [ 451 | getTextFormField("Initial Value"), 452 | getTextFormField("Initial Value Two"), 453 | ] 454 | Align( 455 | alignment: Alignment.bottomRight, 456 | child: Padding( 457 | padding: const EdgeInsets.only(top: 8.0), 458 | child: MaterialButton( 459 | textColor: Colors.amberAccent, 460 | child: Text("SUBMIT"), 461 | onPressed: () { 462 | flush.dismiss([_controller1.value.text, _controller2.value.text]); 463 | }, 464 | ), 465 | ), 466 | ) 467 | ],),), 468 | )..show(context).then((result) { 469 | if (result != null) { 470 | String userInput1 = result[0]; 471 | String userInput2 = result[1]; 472 | } 473 | }); 474 | ``` 475 | 476 | This example tries to mimic the [Material Design style guide](https://material.io/design/components/text-fields.html#anatomy) 477 | 478 | ![Bar input](https://github.com/cmdrootaccess/another-flushbar/raw/main/readme_resources/input_bar.png) 479 | 480 | ### RTL text 481 | 482 | ![RTL Text](https://github.com/cmdrootaccess/another-flushbar/raw/main/readme_resources/rtl_bar.png) 483 | 484 | You can add `textDirection: Directionality.of(context)` for rtl. 485 | 486 | ```dart 487 | Flushbar( 488 | message: "لوريم إيبسوم هو ببساطة نص شكلي يستخدم في صناعة الطباعة والتنضيد", 489 | icon: Icon( 490 | Icons.info_outline, 491 | size: 28.0, 492 | color: Colors.blue[300], 493 | ), 494 | margin: EdgeInsets.all(6.0), 495 | flushbarStyle: FlushbarStyle.FLOATING, 496 | flushbarPosition: FlushbarPosition.TOP, 497 | textDirection: Directionality.of(context), 498 | borderRadius: BorderRadius.circular(12), 499 | duration: Duration(seconds: 3), 500 | leftBarIndicatorColor: Colors.blue[300], 501 | )..show(context); 502 | ``` 503 | 504 | ## Flushbar Helper 505 | 506 | I made a helper class to facilitate the creation of the most common Flushbars. 507 | 508 | ```dart 509 | FlushbarHelper.createSuccess({message, title, duration}); 510 | FlushbarHelper.createInformation({message, title, duration}); 511 | FlushbarHelper.createError({message, title, duration}); 512 | FlushbarHelper.createAction({message, title, duration flatButton}); 513 | FlushbarHelper.createLoading({message,linearProgressIndicator, title, duration, progressIndicatorController, progressIndicatorBackgroundColor}); 514 | FlushbarHelper.createInputFlushbar({textForm}); 515 | ``` 516 | 517 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 11 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 12 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 13 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 14 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 15 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 16 | AE43D7684848AD66E55F5000 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 89FA0030DDC8AE375CD07954 /* Pods_Runner.framework */; }; 17 | /* End PBXBuildFile section */ 18 | 19 | /* Begin PBXCopyFilesBuildPhase section */ 20 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 21 | isa = PBXCopyFilesBuildPhase; 22 | buildActionMask = 2147483647; 23 | dstPath = ""; 24 | dstSubfolderSpec = 10; 25 | files = ( 26 | ); 27 | name = "Embed Frameworks"; 28 | runOnlyForDeploymentPostprocessing = 0; 29 | }; 30 | /* End PBXCopyFilesBuildPhase section */ 31 | 32 | /* Begin PBXFileReference section */ 33 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 34 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 35 | 1D283147CA76A05B0474F106 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 36 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 37 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 38 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 39 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 40 | 8113E54F0F1E61393898D6F7 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 41 | 89FA0030DDC8AE375CD07954 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 42 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 43 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 44 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 45 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 46 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 47 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 48 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 49 | CE09A55E4E01124515DC3A40 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 50 | /* End PBXFileReference section */ 51 | 52 | /* Begin PBXFrameworksBuildPhase section */ 53 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 54 | isa = PBXFrameworksBuildPhase; 55 | buildActionMask = 2147483647; 56 | files = ( 57 | AE43D7684848AD66E55F5000 /* Pods_Runner.framework in Frameworks */, 58 | ); 59 | runOnlyForDeploymentPostprocessing = 0; 60 | }; 61 | /* End PBXFrameworksBuildPhase section */ 62 | 63 | /* Begin PBXGroup section */ 64 | 5F1245786B26EB128502322A /* Frameworks */ = { 65 | isa = PBXGroup; 66 | children = ( 67 | 89FA0030DDC8AE375CD07954 /* Pods_Runner.framework */, 68 | ); 69 | name = Frameworks; 70 | sourceTree = ""; 71 | }; 72 | 9740EEB11CF90186004384FC /* Flutter */ = { 73 | isa = PBXGroup; 74 | children = ( 75 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 76 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 77 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 78 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 79 | ); 80 | name = Flutter; 81 | sourceTree = ""; 82 | }; 83 | 97C146E51CF9000F007C117D = { 84 | isa = PBXGroup; 85 | children = ( 86 | 9740EEB11CF90186004384FC /* Flutter */, 87 | 97C146F01CF9000F007C117D /* Runner */, 88 | 97C146EF1CF9000F007C117D /* Products */, 89 | FB2A5CCAFD87C6238F76D6B1 /* Pods */, 90 | 5F1245786B26EB128502322A /* Frameworks */, 91 | ); 92 | sourceTree = ""; 93 | }; 94 | 97C146EF1CF9000F007C117D /* Products */ = { 95 | isa = PBXGroup; 96 | children = ( 97 | 97C146EE1CF9000F007C117D /* Runner.app */, 98 | ); 99 | name = Products; 100 | sourceTree = ""; 101 | }; 102 | 97C146F01CF9000F007C117D /* Runner */ = { 103 | isa = PBXGroup; 104 | children = ( 105 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 106 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 107 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 108 | 97C147021CF9000F007C117D /* Info.plist */, 109 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 110 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 111 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, 112 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, 113 | ); 114 | path = Runner; 115 | sourceTree = ""; 116 | }; 117 | FB2A5CCAFD87C6238F76D6B1 /* Pods */ = { 118 | isa = PBXGroup; 119 | children = ( 120 | 1D283147CA76A05B0474F106 /* Pods-Runner.debug.xcconfig */, 121 | CE09A55E4E01124515DC3A40 /* Pods-Runner.release.xcconfig */, 122 | 8113E54F0F1E61393898D6F7 /* Pods-Runner.profile.xcconfig */, 123 | ); 124 | name = Pods; 125 | path = Pods; 126 | sourceTree = ""; 127 | }; 128 | /* End PBXGroup section */ 129 | 130 | /* Begin PBXNativeTarget section */ 131 | 97C146ED1CF9000F007C117D /* Runner */ = { 132 | isa = PBXNativeTarget; 133 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 134 | buildPhases = ( 135 | 15B4DD1E83109262CF345277 /* [CP] Check Pods Manifest.lock */, 136 | 9740EEB61CF901F6004384FC /* Run Script */, 137 | 97C146EA1CF9000F007C117D /* Sources */, 138 | 97C146EB1CF9000F007C117D /* Frameworks */, 139 | 97C146EC1CF9000F007C117D /* Resources */, 140 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 141 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 142 | ); 143 | buildRules = ( 144 | ); 145 | dependencies = ( 146 | ); 147 | name = Runner; 148 | productName = Runner; 149 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 150 | productType = "com.apple.product-type.application"; 151 | }; 152 | /* End PBXNativeTarget section */ 153 | 154 | /* Begin PBXProject section */ 155 | 97C146E61CF9000F007C117D /* Project object */ = { 156 | isa = PBXProject; 157 | attributes = { 158 | LastUpgradeCheck = 1020; 159 | ORGANIZATIONNAME = ""; 160 | TargetAttributes = { 161 | 97C146ED1CF9000F007C117D = { 162 | CreatedOnToolsVersion = 7.3.1; 163 | LastSwiftMigration = 1100; 164 | }; 165 | }; 166 | }; 167 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 168 | compatibilityVersion = "Xcode 9.3"; 169 | developmentRegion = en; 170 | hasScannedForEncodings = 0; 171 | knownRegions = ( 172 | en, 173 | Base, 174 | ); 175 | mainGroup = 97C146E51CF9000F007C117D; 176 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 177 | projectDirPath = ""; 178 | projectRoot = ""; 179 | targets = ( 180 | 97C146ED1CF9000F007C117D /* Runner */, 181 | ); 182 | }; 183 | /* End PBXProject section */ 184 | 185 | /* Begin PBXResourcesBuildPhase section */ 186 | 97C146EC1CF9000F007C117D /* Resources */ = { 187 | isa = PBXResourcesBuildPhase; 188 | buildActionMask = 2147483647; 189 | files = ( 190 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 191 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 192 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 193 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 194 | ); 195 | runOnlyForDeploymentPostprocessing = 0; 196 | }; 197 | /* End PBXResourcesBuildPhase section */ 198 | 199 | /* Begin PBXShellScriptBuildPhase section */ 200 | 15B4DD1E83109262CF345277 /* [CP] Check Pods Manifest.lock */ = { 201 | isa = PBXShellScriptBuildPhase; 202 | buildActionMask = 2147483647; 203 | files = ( 204 | ); 205 | inputFileListPaths = ( 206 | ); 207 | inputPaths = ( 208 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 209 | "${PODS_ROOT}/Manifest.lock", 210 | ); 211 | name = "[CP] Check Pods Manifest.lock"; 212 | outputFileListPaths = ( 213 | ); 214 | outputPaths = ( 215 | "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", 216 | ); 217 | runOnlyForDeploymentPostprocessing = 0; 218 | shellPath = /bin/sh; 219 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 220 | showEnvVarsInLog = 0; 221 | }; 222 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 223 | isa = PBXShellScriptBuildPhase; 224 | buildActionMask = 2147483647; 225 | files = ( 226 | ); 227 | inputPaths = ( 228 | ); 229 | name = "Thin Binary"; 230 | outputPaths = ( 231 | ); 232 | runOnlyForDeploymentPostprocessing = 0; 233 | shellPath = /bin/sh; 234 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; 235 | }; 236 | 9740EEB61CF901F6004384FC /* Run Script */ = { 237 | isa = PBXShellScriptBuildPhase; 238 | buildActionMask = 2147483647; 239 | files = ( 240 | ); 241 | inputPaths = ( 242 | ); 243 | name = "Run Script"; 244 | outputPaths = ( 245 | ); 246 | runOnlyForDeploymentPostprocessing = 0; 247 | shellPath = /bin/sh; 248 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 249 | }; 250 | /* End PBXShellScriptBuildPhase section */ 251 | 252 | /* Begin PBXSourcesBuildPhase section */ 253 | 97C146EA1CF9000F007C117D /* Sources */ = { 254 | isa = PBXSourcesBuildPhase; 255 | buildActionMask = 2147483647; 256 | files = ( 257 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 258 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 259 | ); 260 | runOnlyForDeploymentPostprocessing = 0; 261 | }; 262 | /* End PBXSourcesBuildPhase section */ 263 | 264 | /* Begin PBXVariantGroup section */ 265 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 266 | isa = PBXVariantGroup; 267 | children = ( 268 | 97C146FB1CF9000F007C117D /* Base */, 269 | ); 270 | name = Main.storyboard; 271 | sourceTree = ""; 272 | }; 273 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 274 | isa = PBXVariantGroup; 275 | children = ( 276 | 97C147001CF9000F007C117D /* Base */, 277 | ); 278 | name = LaunchScreen.storyboard; 279 | sourceTree = ""; 280 | }; 281 | /* End PBXVariantGroup section */ 282 | 283 | /* Begin XCBuildConfiguration section */ 284 | 249021D3217E4FDB00AE95B9 /* Profile */ = { 285 | isa = XCBuildConfiguration; 286 | buildSettings = { 287 | ALWAYS_SEARCH_USER_PATHS = NO; 288 | CLANG_ANALYZER_NONNULL = YES; 289 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 290 | CLANG_CXX_LIBRARY = "libc++"; 291 | CLANG_ENABLE_MODULES = YES; 292 | CLANG_ENABLE_OBJC_ARC = YES; 293 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 294 | CLANG_WARN_BOOL_CONVERSION = YES; 295 | CLANG_WARN_COMMA = YES; 296 | CLANG_WARN_CONSTANT_CONVERSION = YES; 297 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 298 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 299 | CLANG_WARN_EMPTY_BODY = YES; 300 | CLANG_WARN_ENUM_CONVERSION = YES; 301 | CLANG_WARN_INFINITE_RECURSION = YES; 302 | CLANG_WARN_INT_CONVERSION = YES; 303 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 304 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 305 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 306 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 307 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 308 | CLANG_WARN_STRICT_PROTOTYPES = YES; 309 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 310 | CLANG_WARN_UNREACHABLE_CODE = YES; 311 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 312 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 313 | COPY_PHASE_STRIP = NO; 314 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 315 | ENABLE_NS_ASSERTIONS = NO; 316 | ENABLE_STRICT_OBJC_MSGSEND = YES; 317 | GCC_C_LANGUAGE_STANDARD = gnu99; 318 | GCC_NO_COMMON_BLOCKS = YES; 319 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 320 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 321 | GCC_WARN_UNDECLARED_SELECTOR = YES; 322 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 323 | GCC_WARN_UNUSED_FUNCTION = YES; 324 | GCC_WARN_UNUSED_VARIABLE = YES; 325 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 326 | MTL_ENABLE_DEBUG_INFO = NO; 327 | SDKROOT = iphoneos; 328 | SUPPORTED_PLATFORMS = iphoneos; 329 | TARGETED_DEVICE_FAMILY = "1,2"; 330 | VALIDATE_PRODUCT = YES; 331 | }; 332 | name = Profile; 333 | }; 334 | 249021D4217E4FDB00AE95B9 /* Profile */ = { 335 | isa = XCBuildConfiguration; 336 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 337 | buildSettings = { 338 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 339 | CLANG_ENABLE_MODULES = YES; 340 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 341 | ENABLE_BITCODE = NO; 342 | INFOPLIST_FILE = Runner/Info.plist; 343 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 344 | PRODUCT_BUNDLE_IDENTIFIER = com.hamidwakili.anotherFlushbarExample; 345 | PRODUCT_NAME = "$(TARGET_NAME)"; 346 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 347 | SWIFT_VERSION = 5.0; 348 | VERSIONING_SYSTEM = "apple-generic"; 349 | }; 350 | name = Profile; 351 | }; 352 | 97C147031CF9000F007C117D /* Debug */ = { 353 | isa = XCBuildConfiguration; 354 | buildSettings = { 355 | ALWAYS_SEARCH_USER_PATHS = NO; 356 | CLANG_ANALYZER_NONNULL = YES; 357 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 358 | CLANG_CXX_LIBRARY = "libc++"; 359 | CLANG_ENABLE_MODULES = YES; 360 | CLANG_ENABLE_OBJC_ARC = YES; 361 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 362 | CLANG_WARN_BOOL_CONVERSION = YES; 363 | CLANG_WARN_COMMA = YES; 364 | CLANG_WARN_CONSTANT_CONVERSION = YES; 365 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 366 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 367 | CLANG_WARN_EMPTY_BODY = YES; 368 | CLANG_WARN_ENUM_CONVERSION = YES; 369 | CLANG_WARN_INFINITE_RECURSION = YES; 370 | CLANG_WARN_INT_CONVERSION = YES; 371 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 372 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 373 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 374 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 375 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 376 | CLANG_WARN_STRICT_PROTOTYPES = YES; 377 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 378 | CLANG_WARN_UNREACHABLE_CODE = YES; 379 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 380 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 381 | COPY_PHASE_STRIP = NO; 382 | DEBUG_INFORMATION_FORMAT = dwarf; 383 | ENABLE_STRICT_OBJC_MSGSEND = YES; 384 | ENABLE_TESTABILITY = YES; 385 | GCC_C_LANGUAGE_STANDARD = gnu99; 386 | GCC_DYNAMIC_NO_PIC = NO; 387 | GCC_NO_COMMON_BLOCKS = YES; 388 | GCC_OPTIMIZATION_LEVEL = 0; 389 | GCC_PREPROCESSOR_DEFINITIONS = ( 390 | "DEBUG=1", 391 | "$(inherited)", 392 | ); 393 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 394 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 395 | GCC_WARN_UNDECLARED_SELECTOR = YES; 396 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 397 | GCC_WARN_UNUSED_FUNCTION = YES; 398 | GCC_WARN_UNUSED_VARIABLE = YES; 399 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 400 | MTL_ENABLE_DEBUG_INFO = YES; 401 | ONLY_ACTIVE_ARCH = YES; 402 | SDKROOT = iphoneos; 403 | TARGETED_DEVICE_FAMILY = "1,2"; 404 | }; 405 | name = Debug; 406 | }; 407 | 97C147041CF9000F007C117D /* Release */ = { 408 | isa = XCBuildConfiguration; 409 | buildSettings = { 410 | ALWAYS_SEARCH_USER_PATHS = NO; 411 | CLANG_ANALYZER_NONNULL = YES; 412 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 413 | CLANG_CXX_LIBRARY = "libc++"; 414 | CLANG_ENABLE_MODULES = YES; 415 | CLANG_ENABLE_OBJC_ARC = YES; 416 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 417 | CLANG_WARN_BOOL_CONVERSION = YES; 418 | CLANG_WARN_COMMA = YES; 419 | CLANG_WARN_CONSTANT_CONVERSION = YES; 420 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 421 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 422 | CLANG_WARN_EMPTY_BODY = YES; 423 | CLANG_WARN_ENUM_CONVERSION = YES; 424 | CLANG_WARN_INFINITE_RECURSION = YES; 425 | CLANG_WARN_INT_CONVERSION = YES; 426 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 427 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 428 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 429 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 430 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 431 | CLANG_WARN_STRICT_PROTOTYPES = YES; 432 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 433 | CLANG_WARN_UNREACHABLE_CODE = YES; 434 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 435 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 436 | COPY_PHASE_STRIP = NO; 437 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 438 | ENABLE_NS_ASSERTIONS = NO; 439 | ENABLE_STRICT_OBJC_MSGSEND = YES; 440 | GCC_C_LANGUAGE_STANDARD = gnu99; 441 | GCC_NO_COMMON_BLOCKS = YES; 442 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 443 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 444 | GCC_WARN_UNDECLARED_SELECTOR = YES; 445 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 446 | GCC_WARN_UNUSED_FUNCTION = YES; 447 | GCC_WARN_UNUSED_VARIABLE = YES; 448 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 449 | MTL_ENABLE_DEBUG_INFO = NO; 450 | SDKROOT = iphoneos; 451 | SUPPORTED_PLATFORMS = iphoneos; 452 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 453 | TARGETED_DEVICE_FAMILY = "1,2"; 454 | VALIDATE_PRODUCT = YES; 455 | }; 456 | name = Release; 457 | }; 458 | 97C147061CF9000F007C117D /* Debug */ = { 459 | isa = XCBuildConfiguration; 460 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 461 | buildSettings = { 462 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 463 | CLANG_ENABLE_MODULES = YES; 464 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 465 | ENABLE_BITCODE = NO; 466 | INFOPLIST_FILE = Runner/Info.plist; 467 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 468 | PRODUCT_BUNDLE_IDENTIFIER = com.hamidwakili.anotherFlushbarExample; 469 | PRODUCT_NAME = "$(TARGET_NAME)"; 470 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 471 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 472 | SWIFT_VERSION = 5.0; 473 | VERSIONING_SYSTEM = "apple-generic"; 474 | }; 475 | name = Debug; 476 | }; 477 | 97C147071CF9000F007C117D /* Release */ = { 478 | isa = XCBuildConfiguration; 479 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 480 | buildSettings = { 481 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 482 | CLANG_ENABLE_MODULES = YES; 483 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 484 | ENABLE_BITCODE = NO; 485 | INFOPLIST_FILE = Runner/Info.plist; 486 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 487 | PRODUCT_BUNDLE_IDENTIFIER = com.hamidwakili.anotherFlushbarExample; 488 | PRODUCT_NAME = "$(TARGET_NAME)"; 489 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 490 | SWIFT_VERSION = 5.0; 491 | VERSIONING_SYSTEM = "apple-generic"; 492 | }; 493 | name = Release; 494 | }; 495 | /* End XCBuildConfiguration section */ 496 | 497 | /* Begin XCConfigurationList section */ 498 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 499 | isa = XCConfigurationList; 500 | buildConfigurations = ( 501 | 97C147031CF9000F007C117D /* Debug */, 502 | 97C147041CF9000F007C117D /* Release */, 503 | 249021D3217E4FDB00AE95B9 /* Profile */, 504 | ); 505 | defaultConfigurationIsVisible = 0; 506 | defaultConfigurationName = Release; 507 | }; 508 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 509 | isa = XCConfigurationList; 510 | buildConfigurations = ( 511 | 97C147061CF9000F007C117D /* Debug */, 512 | 97C147071CF9000F007C117D /* Release */, 513 | 249021D4217E4FDB00AE95B9 /* Profile */, 514 | ); 515 | defaultConfigurationIsVisible = 0; 516 | defaultConfigurationName = Release; 517 | }; 518 | /* End XCConfigurationList section */ 519 | }; 520 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 521 | } 522 | -------------------------------------------------------------------------------- /lib/flushbar.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:ui'; 3 | 4 | import 'package:flutter/material.dart'; 5 | import 'package:flutter/scheduler.dart'; 6 | 7 | import 'flushbar_route.dart' as route; 8 | 9 | // ignore: constant_identifier_names 10 | const String FLUSHBAR_ROUTE_NAME = '/flushbarRoute'; 11 | 12 | typedef FlushbarStatusCallback = void Function(FlushbarStatus? status); 13 | typedef OnTap = void Function(Flushbar flushbar); 14 | 15 | /// A highly customizable widget so you can notify your user when you fell like he needs a beautiful explanation. 16 | // ignore: must_be_immutable 17 | class Flushbar extends StatefulWidget { 18 | Flushbar( 19 | {Key? key, 20 | this.title, 21 | this.titleColor, 22 | this.titleSize, 23 | this.message, 24 | this.messageSize, 25 | this.messageColor, 26 | this.titleText, 27 | this.messageText, 28 | this.icon, 29 | this.shouldIconPulse = true, 30 | this.maxWidth, 31 | this.margin = const EdgeInsets.all(0.0), 32 | this.padding = const EdgeInsets.all(16), 33 | this.borderRadius, 34 | this.textDirection = TextDirection.ltr, 35 | this.borderColor, 36 | this.borderWidth = 1.0, 37 | this.backgroundColor = const Color(0xFF303030), 38 | this.leftBarIndicatorColor, 39 | this.boxShadows, 40 | this.backgroundGradient, 41 | this.mainButton, 42 | this.onTap, 43 | this.duration, 44 | this.isDismissible = true, 45 | this.dismissDirection = FlushbarDismissDirection.VERTICAL, 46 | this.showProgressIndicator = false, 47 | this.progressIndicatorController, 48 | this.progressIndicatorBackgroundColor, 49 | this.progressIndicatorValueColor, 50 | this.flushbarPosition = FlushbarPosition.BOTTOM, 51 | this.positionOffset = 0.0, 52 | this.flushbarStyle = FlushbarStyle.FLOATING, 53 | this.forwardAnimationCurve = Curves.easeOutCirc, 54 | this.reverseAnimationCurve = Curves.easeOutCirc, 55 | this.animationDuration = const Duration(seconds: 1), 56 | FlushbarStatusCallback? onStatusChanged, 57 | this.barBlur = 0.0, 58 | this.blockBackgroundInteraction = false, 59 | this.routeBlur, 60 | this.routeColor, 61 | this.userInputForm, 62 | this.endOffset, 63 | this.flushbarRoute // Please dont init this 64 | }) 65 | // ignore: prefer_initializing_formals 66 | : onStatusChanged = onStatusChanged, 67 | super(key: key) { 68 | onStatusChanged = onStatusChanged ?? (status) {}; 69 | } 70 | 71 | /// A callback for you to listen to the different Flushbar status 72 | final FlushbarStatusCallback? onStatusChanged; 73 | 74 | /// The title displayed to the user 75 | final String? title; 76 | 77 | /// The title text size displayed to the user 78 | final double? titleSize; 79 | 80 | /// Color title displayed to the user ? default is black 81 | final Color? titleColor; 82 | 83 | /// The message displayed to the user. 84 | final String? message; 85 | 86 | /// The message text size displayed to the user. 87 | final double? messageSize; 88 | 89 | /// Color message displayed to the user ? default is black 90 | final Color? messageColor; 91 | 92 | /// Replaces [title]. Although this accepts a [Widget], it is meant to receive [Text] or [RichText] 93 | final Widget? titleText; 94 | 95 | /// Replaces [message]. Although this accepts a [Widget], it is meant to receive [Text] or [RichText] 96 | final Widget? messageText; 97 | 98 | /// Will be ignored if [backgroundGradient] is not null 99 | final Color backgroundColor; 100 | 101 | /// If not null, shows a left vertical bar to better indicate the humor of the notification. 102 | /// It is not possible to use it with a [Form] and I do not recommend using it with [LinearProgressIndicator] 103 | final Color? leftBarIndicatorColor; 104 | 105 | /// [boxShadows] The shadows generated by Flushbar. Leave it null if you don't want a shadow. 106 | /// You can use more than one if you feel the need. 107 | /// Check (this example)[https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/material/shadows.dart] 108 | final List? boxShadows; 109 | 110 | /// Makes [backgroundColor] be ignored. 111 | final Gradient? backgroundGradient; 112 | 113 | /// You can use any widget here, but I recommend [Icon] or [Image] as indication of what kind 114 | /// of message you are displaying. Other widgets may break the layout 115 | final Widget? icon; 116 | 117 | /// An option to animate the icon (if present). Defaults to true. 118 | final bool shouldIconPulse; 119 | 120 | /// Use if you need an action from the user. [TextButton] is recommended here 121 | final Widget? mainButton; 122 | 123 | /// A callback that registers the user's click anywhere. An alternative to [mainButton] 124 | final OnTap? onTap; 125 | 126 | /// How long until Flushbar will hide itself (be dismissed). To make it indefinite, leave it null. 127 | final Duration? duration; 128 | 129 | /// True if you want to show a [LinearProgressIndicator]. 130 | /// If [progressIndicatorController] is null, an infinite progress indicator will be shown 131 | final bool showProgressIndicator; 132 | 133 | /// An optional [AnimationController] when you want to control the progress of your [LinearProgressIndicator]. 134 | /// You are responsible for controlling the progress 135 | final AnimationController? progressIndicatorController; 136 | 137 | /// A [LinearProgressIndicator] configuration parameter. 138 | final Color? progressIndicatorBackgroundColor; 139 | 140 | /// A [LinearProgressIndicator] configuration parameter. 141 | final Animation? progressIndicatorValueColor; 142 | 143 | /// Determines if the user can swipe or click the overlay (if [routeBlur] > 0) to dismiss. 144 | /// It is recommended that you set [duration] != null if this is false. 145 | /// If the user swipes to dismiss or clicks the overlay, no value will be returned. 146 | final bool isDismissible; 147 | 148 | /// Used to limit Flushbar width (usually on large screens) 149 | final double? maxWidth; 150 | 151 | /// Adds a custom margin to Flushbar 152 | final EdgeInsets margin; 153 | 154 | /// Adds a custom padding to Flushbar 155 | /// The default follows material design guide line 156 | final EdgeInsets padding; 157 | 158 | /// Adds a radius to corners specified of Flushbar. Best combined with [margin]. 159 | /// I do not recommend using it with [showProgressIndicator] or [leftBarIndicatorColor]. 160 | final BorderRadius? borderRadius; 161 | 162 | /// [TextDirection.ltr] by default 163 | /// added to support rtl languages 164 | final TextDirection textDirection; 165 | 166 | // Adds a border to every side of Flushbar 167 | /// I do not recommend using it with [showProgressIndicator] or [leftBarIndicatorColor]. 168 | final Color? borderColor; 169 | 170 | /// Changes the width of the border if [borderColor] is specified 171 | final double borderWidth; 172 | 173 | /// Flushbar can be based on [FlushbarPosition.TOP] or on [FlushbarPosition.BOTTOM] of your screen. 174 | /// [FlushbarPosition.BOTTOM] is the default. 175 | final FlushbarPosition flushbarPosition; 176 | 177 | final double positionOffset; 178 | 179 | /// [FlushbarDismissDirection.VERTICAL] by default. 180 | /// Can also be [FlushbarDismissDirection.HORIZONTAL] in which case both left and right dismiss are allowed. 181 | final FlushbarDismissDirection dismissDirection; 182 | 183 | /// Flushbar can be floating or be grounded to the edge of the screen. 184 | /// If grounded, I do not recommend using [margin] or [borderRadius]. [FlushbarStyle.FLOATING] is the default 185 | /// If grounded, I do not recommend using a [backgroundColor] with transparency or [barBlur] 186 | final FlushbarStyle flushbarStyle; 187 | 188 | /// The [Curve] animation used when show() is called. [Curves.easeOut] is default 189 | final Curve forwardAnimationCurve; 190 | 191 | /// The [Curve] animation used when dismiss() is called. [Curves.fastOutSlowIn] is default 192 | final Curve reverseAnimationCurve; 193 | 194 | /// Use it to speed up or slow down the animation duration 195 | final Duration animationDuration; 196 | 197 | /// Default is 0.0. If different than 0.0, blurs only Flushbar's background. 198 | /// To take effect, make sure your [backgroundColor] has some opacity. 199 | /// The greater the value, the greater the blur. 200 | final double barBlur; 201 | 202 | /// Determines if user can interact with the screen behind it 203 | /// If this is false, [routeBlur] and [routeColor] will be ignored 204 | final bool blockBackgroundInteraction; 205 | 206 | /// Default is 0.0. If different than 0.0, creates a blurred 207 | /// overlay that prevents the user from interacting with the screen. 208 | /// The greater the value, the greater the blur. 209 | /// It does not take effect if [blockBackgroundInteraction] is false 210 | final double? routeBlur; 211 | 212 | /// Default is [Colors.transparent]. Only takes effect if [routeBlur] > 0.0. 213 | /// Make sure you use a color with transparency here e.g. Colors.grey[600].withOpacity(0.2). 214 | /// It does not take effect if [blockBackgroundInteraction] is false 215 | final Color? routeColor; 216 | 217 | /// A [TextFormField] in case you want a simple user input. Every other widget is ignored if this is not null. 218 | final Form? userInputForm; 219 | 220 | /// Offset to be added to the end Flushbar position. 221 | /// Intended to replace [margin] when you need items below Flushbar to be accessible 222 | final Offset? endOffset; 223 | 224 | route.FlushbarRoute? flushbarRoute; 225 | 226 | /// Show the flushbar. Kicks in [FlushbarStatus.IS_APPEARING] state followed by [FlushbarStatus.SHOWING] 227 | Future show(BuildContext context) async { 228 | flushbarRoute = route.showFlushbar( 229 | context: context, 230 | flushbar: this, 231 | ) as route.FlushbarRoute; 232 | 233 | return await Navigator.of(context, rootNavigator: false) 234 | .push(flushbarRoute as Route); 235 | } 236 | 237 | /// Dismisses the flushbar causing is to return a future containing [result]. 238 | /// When this future finishes, it is guaranteed that Flushbar was dismissed. 239 | Future dismiss([T? result]) async { 240 | // If route was never initialized, do nothing 241 | if (flushbarRoute == null) { 242 | return null; 243 | } 244 | 245 | if (flushbarRoute!.isCurrent) { 246 | flushbarRoute!.navigator!.pop(result); 247 | return flushbarRoute!.completed; 248 | } else if (flushbarRoute!.isActive) { 249 | // removeRoute is called every time you dismiss a Flushbar that is not the top route. 250 | // It will not animate back and listeners will not detect FlushbarStatus.IS_HIDING or FlushbarStatus.DISMISSED 251 | // To avoid this, always make sure that Flushbar is the top route when it is being dismissed 252 | flushbarRoute!.navigator!.removeRoute(flushbarRoute!); 253 | } 254 | 255 | return null; 256 | } 257 | 258 | /// Checks if the flushbar is visible 259 | bool isShowing() { 260 | if (flushbarRoute == null) { 261 | return false; 262 | } 263 | return flushbarRoute!.currentStatus == FlushbarStatus.SHOWING; 264 | } 265 | 266 | /// Checks if the flushbar is dismissed 267 | bool isDismissed() { 268 | if (flushbarRoute == null) { 269 | return false; 270 | } 271 | return flushbarRoute!.currentStatus == FlushbarStatus.DISMISSED; 272 | } 273 | 274 | bool isAppearing() { 275 | if (flushbarRoute == null) { 276 | return false; 277 | } 278 | return flushbarRoute!.currentStatus == FlushbarStatus.IS_APPEARING; 279 | } 280 | 281 | bool isHiding() { 282 | if (flushbarRoute == null) { 283 | return false; 284 | } 285 | return flushbarRoute!.currentStatus == FlushbarStatus.IS_HIDING; 286 | } 287 | 288 | @override 289 | State createState() => _FlushbarState(); 290 | } 291 | 292 | class _FlushbarState extends State> 293 | with TickerProviderStateMixin { 294 | final Duration _pulseAnimationDuration = const Duration(seconds: 1); 295 | final Widget _emptyWidget = const SizedBox(); 296 | final double _initialOpacity = 1.0; 297 | final double _finalOpacity = 0.4; 298 | 299 | GlobalKey? _backgroundBoxKey; 300 | FlushbarStatus? currentStatus; 301 | AnimationController? _fadeController; 302 | late Animation _fadeAnimation; 303 | late bool _isTitlePresent; 304 | late double _messageTopMargin; 305 | FocusScopeNode? _focusNode; 306 | late FocusAttachment _focusAttachment; 307 | late Completer _boxHeightCompleter; 308 | 309 | CurvedAnimation? _progressAnimation; 310 | 311 | @override 312 | void initState() { 313 | super.initState(); 314 | 315 | _backgroundBoxKey = GlobalKey(); 316 | _boxHeightCompleter = Completer(); 317 | 318 | assert( 319 | widget.userInputForm != null || 320 | ((widget.message != null && widget.message!.isNotEmpty) || 321 | widget.messageText != null), 322 | 'A message is mandatory if you are not using userInputForm. Set either a message or messageText'); 323 | 324 | _isTitlePresent = (widget.title != null || widget.titleText != null); 325 | _messageTopMargin = _isTitlePresent ? 6.0 : widget.padding.top; 326 | 327 | _configureLeftBarFuture(); 328 | _configureProgressIndicatorAnimation(); 329 | 330 | if (widget.icon != null && widget.shouldIconPulse) { 331 | _configurePulseAnimation(); 332 | _fadeController?.forward(); 333 | } 334 | 335 | _focusNode = FocusScopeNode(); 336 | _focusAttachment = _focusNode!.attach(context); 337 | } 338 | 339 | @override 340 | void dispose() { 341 | _fadeController?.dispose(); 342 | widget.progressIndicatorController?.dispose(); 343 | 344 | _focusAttachment.detach(); 345 | _focusNode!.dispose(); 346 | super.dispose(); 347 | } 348 | 349 | void _configureLeftBarFuture() { 350 | SchedulerBinding.instance.addPostFrameCallback( 351 | (_) { 352 | final keyContext = _backgroundBoxKey!.currentContext; 353 | 354 | if (keyContext != null) { 355 | final box = keyContext.findRenderObject() as RenderBox; 356 | _boxHeightCompleter.complete(box.size); 357 | } 358 | }, 359 | ); 360 | } 361 | 362 | void _configureProgressIndicatorAnimation() { 363 | if (widget.showProgressIndicator && 364 | widget.progressIndicatorController != null) { 365 | _progressAnimation = CurvedAnimation( 366 | curve: Curves.linear, parent: widget.progressIndicatorController!); 367 | } 368 | } 369 | 370 | void _configurePulseAnimation() { 371 | _fadeController = 372 | AnimationController(vsync: this, duration: _pulseAnimationDuration); 373 | _fadeAnimation = Tween(begin: _initialOpacity, end: _finalOpacity).animate( 374 | CurvedAnimation( 375 | parent: _fadeController!, 376 | curve: Curves.linear, 377 | ), 378 | ); 379 | 380 | _fadeController!.addStatusListener((status) { 381 | if (status == AnimationStatus.completed) { 382 | _fadeController!.reverse(); 383 | } 384 | if (status == AnimationStatus.dismissed) { 385 | _fadeController!.forward(); 386 | } 387 | }); 388 | 389 | _fadeController!.forward(); 390 | } 391 | 392 | //TODO : review EdgeInsets 393 | @override 394 | Widget build(BuildContext context) { 395 | return Align( 396 | heightFactor: 1.0, 397 | child: Material( 398 | color: widget.flushbarStyle == FlushbarStyle.FLOATING 399 | ? Colors.transparent 400 | : widget.backgroundColor, 401 | child: SafeArea( 402 | minimum: widget.flushbarPosition == FlushbarPosition.BOTTOM 403 | ? EdgeInsets.only( 404 | bottom: MediaQuery.of(context).viewInsets.bottom) 405 | : EdgeInsets.only(top: MediaQuery.of(context).viewInsets.top), 406 | // ? EdgeInsets.only( 407 | // bottom: (MediaQuery.of(context).padding.bottom + 408 | // widget.positionOffset)) 409 | // : EdgeInsets.only( 410 | // top: (MediaQuery.of(context).padding.top) + 411 | // widget.positionOffset), 412 | bottom: widget.flushbarPosition == FlushbarPosition.BOTTOM, 413 | top: widget.flushbarPosition == FlushbarPosition.TOP, 414 | left: false, 415 | right: false, 416 | child: _getFlushbar(), 417 | ), 418 | ), 419 | ); 420 | } 421 | 422 | Widget _getFlushbar() { 423 | Widget flushbar; 424 | 425 | if (widget.userInputForm != null) { 426 | flushbar = _generateInputFlushbar(); 427 | } else { 428 | flushbar = _generateFlushbar(); 429 | } 430 | 431 | return Stack( 432 | children: [ 433 | FutureBuilder( 434 | future: _boxHeightCompleter.future, 435 | builder: (context, AsyncSnapshot snapshot) { 436 | if (snapshot.hasData) { 437 | if (widget.barBlur == 0) { 438 | //fixes https://github.com/cmdrootaccess/another-flushbar/issues/8 439 | return _emptyWidget; 440 | } 441 | return ClipRRect( 442 | borderRadius: widget.borderRadius, 443 | child: BackdropFilter( 444 | filter: ImageFilter.blur( 445 | sigmaX: widget.barBlur, sigmaY: widget.barBlur), 446 | child: Container( 447 | height: snapshot.data!.height, 448 | width: snapshot.data!.width, 449 | decoration: BoxDecoration( 450 | color: Colors.transparent, 451 | borderRadius: widget.borderRadius, 452 | ), 453 | ), 454 | ), 455 | ); 456 | } 457 | return _emptyWidget; 458 | }, 459 | ), 460 | flushbar, 461 | ], 462 | ); 463 | } 464 | 465 | Widget _generateInputFlushbar() { 466 | return Container( 467 | key: _backgroundBoxKey, 468 | constraints: widget.maxWidth != null 469 | ? BoxConstraints(maxWidth: widget.maxWidth!) 470 | : null, 471 | decoration: BoxDecoration( 472 | color: widget.backgroundColor, 473 | gradient: widget.backgroundGradient, 474 | boxShadow: widget.boxShadows, 475 | borderRadius: widget.borderRadius, 476 | border: widget.borderColor != null 477 | ? Border.all(color: widget.borderColor!, width: widget.borderWidth) 478 | : null, 479 | ), 480 | child: Padding( 481 | padding: const EdgeInsets.only( 482 | left: 8.0, right: 8.0, bottom: 8.0, top: 16.0), 483 | child: FocusScope( 484 | node: _focusNode, 485 | autofocus: true, 486 | child: widget.userInputForm!, 487 | ), 488 | ), 489 | ); 490 | } 491 | 492 | Widget _generateFlushbar() { 493 | return Container( 494 | key: _backgroundBoxKey, 495 | constraints: widget.maxWidth != null 496 | ? BoxConstraints(maxWidth: widget.maxWidth!) 497 | : null, 498 | decoration: BoxDecoration( 499 | color: widget.backgroundColor, 500 | gradient: widget.backgroundGradient, 501 | boxShadow: widget.boxShadows, 502 | borderRadius: widget.borderRadius, 503 | border: widget.borderColor != null 504 | ? Border.all(color: widget.borderColor!, width: widget.borderWidth) 505 | : null, 506 | ), 507 | child: Column( 508 | mainAxisSize: MainAxisSize.min, 509 | children: [ 510 | _buildProgressIndicator(), 511 | Row( 512 | mainAxisSize: MainAxisSize.max, 513 | children: _getAppropriateRowLayout(), 514 | ), 515 | ], 516 | ), 517 | ); 518 | } 519 | 520 | Widget _buildProgressIndicator() { 521 | if (widget.showProgressIndicator && _progressAnimation != null) { 522 | return AnimatedBuilder( 523 | animation: _progressAnimation!, 524 | builder: (_, __) { 525 | return LinearProgressIndicator( 526 | value: _progressAnimation!.value, 527 | backgroundColor: widget.progressIndicatorBackgroundColor, 528 | valueColor: widget.progressIndicatorValueColor, 529 | ); 530 | }); 531 | } 532 | 533 | if (widget.showProgressIndicator) { 534 | return LinearProgressIndicator( 535 | backgroundColor: widget.progressIndicatorBackgroundColor, 536 | valueColor: widget.progressIndicatorValueColor, 537 | ); 538 | } 539 | 540 | return _emptyWidget; 541 | } 542 | 543 | List _getAppropriateRowLayout() { 544 | double buttonRightPadding; 545 | var iconPadding = 0.0; 546 | if (widget.padding.right - 12 < 0) { 547 | buttonRightPadding = 4; 548 | } else { 549 | buttonRightPadding = widget.padding.right - 12; 550 | } 551 | 552 | if (widget.padding.left > 16.0) { 553 | iconPadding = widget.padding.left; 554 | } 555 | 556 | if (widget.icon == null && widget.mainButton == null) { 557 | return [ 558 | _buildLeftBarIndicator(), 559 | Expanded( 560 | flex: 1, 561 | child: Column( 562 | crossAxisAlignment: CrossAxisAlignment.stretch, 563 | mainAxisSize: MainAxisSize.min, 564 | children: [ 565 | (_isTitlePresent) 566 | ? Padding( 567 | padding: EdgeInsets.only( 568 | top: widget.padding.top, 569 | left: widget.padding.left, 570 | right: widget.padding.right, 571 | ), 572 | child: _getTitleText(), 573 | ) 574 | : _emptyWidget, 575 | Padding( 576 | padding: EdgeInsets.only( 577 | top: _messageTopMargin, 578 | left: widget.padding.left, 579 | right: widget.padding.right, 580 | bottom: widget.padding.bottom, 581 | ), 582 | child: widget.messageText ?? _getDefaultNotificationText(), 583 | ), 584 | ], 585 | ), 586 | ), 587 | ]; 588 | } else if (widget.icon != null && widget.mainButton == null) { 589 | return [ 590 | _buildLeftBarIndicator(), 591 | ConstrainedBox( 592 | constraints: BoxConstraints.tightFor(width: 42.0 + iconPadding), 593 | child: _getIcon(), 594 | ), 595 | Expanded( 596 | flex: 1, 597 | child: Column( 598 | crossAxisAlignment: CrossAxisAlignment.stretch, 599 | mainAxisSize: MainAxisSize.min, 600 | children: [ 601 | (_isTitlePresent) 602 | ? Padding( 603 | padding: EdgeInsets.only( 604 | top: widget.padding.top, 605 | left: 4.0, 606 | right: widget.padding.left, 607 | ), 608 | child: _getTitleText(), 609 | ) 610 | : _emptyWidget, 611 | Padding( 612 | padding: EdgeInsets.only( 613 | top: _messageTopMargin, 614 | left: 4.0, 615 | right: widget.padding.right, 616 | bottom: widget.padding.bottom, 617 | ), 618 | child: widget.messageText ?? _getDefaultNotificationText(), 619 | ), 620 | ], 621 | ), 622 | ), 623 | ]; 624 | } else if (widget.icon == null && widget.mainButton != null) { 625 | return [ 626 | _buildLeftBarIndicator(), 627 | Expanded( 628 | flex: 1, 629 | child: Column( 630 | crossAxisAlignment: CrossAxisAlignment.stretch, 631 | mainAxisSize: MainAxisSize.min, 632 | children: [ 633 | (_isTitlePresent) 634 | ? Padding( 635 | padding: EdgeInsets.only( 636 | top: widget.padding.top, 637 | left: widget.padding.left, 638 | right: widget.padding.right, 639 | ), 640 | child: _getTitleText(), 641 | ) 642 | : _emptyWidget, 643 | Padding( 644 | padding: EdgeInsets.only( 645 | top: _messageTopMargin, 646 | left: widget.padding.left, 647 | right: 8.0, 648 | bottom: widget.padding.bottom, 649 | ), 650 | child: widget.messageText ?? _getDefaultNotificationText(), 651 | ), 652 | ], 653 | ), 654 | ), 655 | Padding( 656 | padding: EdgeInsets.only(right: buttonRightPadding), 657 | child: _getMainActionButton(), 658 | ), 659 | ]; 660 | } else { 661 | return [ 662 | _buildLeftBarIndicator(), 663 | ConstrainedBox( 664 | constraints: BoxConstraints.tightFor(width: 42.0 + iconPadding), 665 | child: _getIcon(), 666 | ), 667 | Expanded( 668 | flex: 1, 669 | child: Column( 670 | crossAxisAlignment: CrossAxisAlignment.stretch, 671 | mainAxisSize: MainAxisSize.min, 672 | children: [ 673 | (_isTitlePresent) 674 | ? Padding( 675 | padding: EdgeInsets.only( 676 | top: widget.padding.top, 677 | left: 4.0, 678 | right: 8.0, 679 | ), 680 | child: _getTitleText(), 681 | ) 682 | : _emptyWidget, 683 | Padding( 684 | padding: EdgeInsets.only( 685 | top: _messageTopMargin, 686 | left: 4.0, 687 | right: 8.0, 688 | bottom: widget.padding.bottom, 689 | ), 690 | child: widget.messageText ?? _getDefaultNotificationText(), 691 | ), 692 | ], 693 | ), 694 | ), 695 | _getMainActionButton() != null 696 | ? Padding( 697 | padding: EdgeInsets.only(right: buttonRightPadding), 698 | child: _getMainActionButton(), 699 | ) 700 | : _emptyWidget, 701 | ]; 702 | } 703 | } 704 | 705 | Widget _buildLeftBarIndicator() { 706 | if (widget.leftBarIndicatorColor != null) { 707 | return FutureBuilder( 708 | future: _boxHeightCompleter.future, 709 | builder: (BuildContext buildContext, AsyncSnapshot snapshot) { 710 | if (snapshot.hasData) { 711 | return Container( 712 | width: 8.0, 713 | height: snapshot.data!.height, 714 | decoration: BoxDecoration( 715 | borderRadius: widget.borderRadius == null 716 | ? null 717 | : widget.textDirection == TextDirection.ltr 718 | ? BorderRadius.only( 719 | topLeft: widget.borderRadius!.topLeft, 720 | bottomLeft: widget.borderRadius!.bottomLeft) 721 | : BorderRadius.only( 722 | topRight: widget.borderRadius!.topRight, 723 | bottomRight: widget.borderRadius!.bottomRight), 724 | color: widget.leftBarIndicatorColor, 725 | ), 726 | ); 727 | } else { 728 | return _emptyWidget; 729 | } 730 | }, 731 | ); 732 | } else { 733 | return _emptyWidget; 734 | } 735 | } 736 | 737 | Widget? _getIcon() { 738 | if (widget.icon != null && widget.icon is Icon && widget.shouldIconPulse) { 739 | return FadeTransition( 740 | opacity: _fadeAnimation, 741 | child: widget.icon, 742 | ); 743 | } else if (widget.icon != null) { 744 | return widget.icon; 745 | } else { 746 | return _emptyWidget; 747 | } 748 | } 749 | 750 | Widget? _getTitleText() { 751 | return widget.titleText ?? 752 | Text( 753 | widget.title ?? '', 754 | style: TextStyle( 755 | fontSize: widget.titleSize ?? 16.0, 756 | color: widget.titleColor ?? Colors.white, 757 | fontWeight: FontWeight.bold), 758 | ); 759 | } 760 | 761 | Text _getDefaultNotificationText() { 762 | return Text( 763 | widget.message ?? '', 764 | style: TextStyle( 765 | fontSize: widget.messageSize ?? 14.0, 766 | color: widget.messageColor ?? Colors.white), 767 | ); 768 | } 769 | 770 | Widget? _getMainActionButton() { 771 | if (widget.mainButton != null) { 772 | return widget.mainButton; 773 | } else { 774 | return null; 775 | } 776 | } 777 | } 778 | 779 | /// Indicates if flushbar is going to start at the [TOP] or at the [BOTTOM] 780 | enum FlushbarPosition { TOP, BOTTOM } 781 | 782 | /// Indicates if flushbar will be attached to the edge of the screen or not 783 | enum FlushbarStyle { FLOATING, GROUNDED } 784 | 785 | /// Indicates the direction in which it is possible to dismiss 786 | /// If vertical, dismiss up will be allowed if [FlushbarPosition.TOP] 787 | /// If vertical, dismiss down will be allowed if [FlushbarPosition.BOTTOM] 788 | enum FlushbarDismissDirection { HORIZONTAL, VERTICAL } 789 | 790 | /// Indicates the animation status 791 | /// [FlushbarStatus.SHOWING] Flushbar has stopped and the user can see it 792 | /// [FlushbarStatus.DISMISSED] Flushbar has finished its mission and returned any pending values 793 | /// [FlushbarStatus.IS_APPEARING] Flushbar is moving towards [FlushbarStatus.SHOWING] 794 | /// [FlushbarStatus.IS_HIDING] Flushbar is moving towards [] [FlushbarStatus.DISMISSED] 795 | enum FlushbarStatus { SHOWING, DISMISSED, IS_APPEARING, IS_HIDING } 796 | --------------------------------------------------------------------------------