├── lib ├── src │ ├── widgets │ │ ├── todo │ │ │ ├── grid_view_plus.dart │ │ │ ├── list_view_plus.dart │ │ │ └── loading_plus.dart │ │ ├── widgets_export_plus.dart │ │ └── src │ │ │ ├── rich_text_plus.dart │ │ │ ├── button_plus.dart │ │ │ ├── text_plus.dart │ │ │ ├── container_plus.dart │ │ │ └── text_field_plus.dart │ ├── extensions │ │ ├── extensions_export_plus.dart │ │ └── src │ │ │ ├── file_extension_plus.dart │ │ │ ├── duration_extension_plus.dart │ │ │ ├── date_extension_plus.dart │ │ │ ├── num_extension_plus.dart │ │ │ └── string_exntension_plus.dart │ ├── utils │ │ ├── utils_export_plus.dart │ │ └── src │ │ │ ├── utils_plus.dart │ │ │ ├── local_storage_plus.dart │ │ │ ├── bottom_sheet_plus.dart │ │ │ ├── snack_bar_plus.dart │ │ │ ├── navigator_plus.dart │ │ │ └── dialog_plus.dart │ └── components │ │ ├── components_export_plus.dart │ │ └── src │ │ ├── inner_shadow_plus.dart │ │ ├── shadow_plus.dart │ │ ├── text_decoration_plus.dart │ │ ├── border_plus.dart │ │ ├── skeleton_plus.dart │ │ ├── radius_plus.dart │ │ ├── inner_shadow_render_plus.dart │ │ ├── skeleton_render_plus.dart │ │ ├── gradient_plus.dart │ │ └── text_field_mask_plus.dart └── flutter_plus.dart ├── 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 │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ └── IDEWorkspaceChecks.plist │ ├── .gitignore │ ├── Podfile.lock │ └── Podfile ├── button_plus_4.gif ├── web │ ├── favicon.png │ ├── icons │ │ ├── Icon-192.png │ │ └── Icon-512.png │ ├── manifest.json │ └── index.html ├── container_plus_3.gif ├── images │ ├── comparativo.png │ ├── text_plus_1.png │ ├── text_plus_2.png │ ├── text_plus_3.png │ ├── button_plus_1.png │ ├── button_plus_2.png │ ├── button_plus_3.png │ ├── container_plus_1.png │ ├── container_plus_2.png │ ├── rich_text_plus.png │ ├── bottom_sheet_plus.png │ ├── dialog_plus_custom.png │ ├── text_field_plus_1.png │ ├── text_field_plus_2.png │ ├── text_field_plus_3.png │ ├── dialog_plus_default.png │ ├── snack_bar_plus_custom.png │ └── snack_bar_plus_default.png ├── 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 │ │ │ │ │ │ └── example │ │ │ │ │ │ └── example │ │ │ │ │ │ └── MainActivity.kt │ │ │ │ └── AndroidManifest.xml │ │ │ ├── debug │ │ │ │ └── AndroidManifest.xml │ │ │ └── profile │ │ │ │ └── AndroidManifest.xml │ │ └── build.gradle │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ ├── .gitignore │ ├── settings.gradle │ └── build.gradle ├── lib │ ├── main.dart │ ├── src │ │ ├── screens │ │ │ ├── navigator_plus_screen.dart │ │ │ ├── rich_text_plus_screen.dart │ │ │ ├── text_plus_screen.dart │ │ │ ├── text_field_plus_screen.dart │ │ │ ├── container_plus_screen.dart │ │ │ ├── compare_widget_screen.dart │ │ │ ├── button_plus_screen.dart │ │ │ └── home_screen.dart │ │ └── widgets │ │ │ └── custom_widget.dart │ └── flutter_plus_example.dart ├── .metadata ├── README.md ├── .gitignore ├── pubspec.yaml └── pubspec.lock ├── .metadata ├── CHANGELOG.md ├── pubspec.yaml ├── LICENSE ├── .gitignore ├── analysis_options.yaml └── pubspec.lock /lib/src/widgets/todo/grid_view_plus.dart: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/src/widgets/todo/list_view_plus.dart: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/src/widgets/todo/loading_plus.dart: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /example/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /example/button_plus_4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbmiranda/flutter_plus/HEAD/example/button_plus_4.gif -------------------------------------------------------------------------------- /example/web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbmiranda/flutter_plus/HEAD/example/web/favicon.png -------------------------------------------------------------------------------- /example/container_plus_3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbmiranda/flutter_plus/HEAD/example/container_plus_3.gif -------------------------------------------------------------------------------- /example/images/comparativo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbmiranda/flutter_plus/HEAD/example/images/comparativo.png -------------------------------------------------------------------------------- /example/images/text_plus_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbmiranda/flutter_plus/HEAD/example/images/text_plus_1.png -------------------------------------------------------------------------------- /example/images/text_plus_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbmiranda/flutter_plus/HEAD/example/images/text_plus_2.png -------------------------------------------------------------------------------- /example/images/text_plus_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbmiranda/flutter_plus/HEAD/example/images/text_plus_3.png -------------------------------------------------------------------------------- /example/web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbmiranda/flutter_plus/HEAD/example/web/icons/Icon-192.png -------------------------------------------------------------------------------- /example/web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbmiranda/flutter_plus/HEAD/example/web/icons/Icon-512.png -------------------------------------------------------------------------------- /example/images/button_plus_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbmiranda/flutter_plus/HEAD/example/images/button_plus_1.png -------------------------------------------------------------------------------- /example/images/button_plus_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbmiranda/flutter_plus/HEAD/example/images/button_plus_2.png -------------------------------------------------------------------------------- /example/images/button_plus_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbmiranda/flutter_plus/HEAD/example/images/button_plus_3.png -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /example/images/container_plus_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbmiranda/flutter_plus/HEAD/example/images/container_plus_1.png -------------------------------------------------------------------------------- /example/images/container_plus_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbmiranda/flutter_plus/HEAD/example/images/container_plus_2.png -------------------------------------------------------------------------------- /example/images/rich_text_plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbmiranda/flutter_plus/HEAD/example/images/rich_text_plus.png -------------------------------------------------------------------------------- /example/images/bottom_sheet_plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbmiranda/flutter_plus/HEAD/example/images/bottom_sheet_plus.png -------------------------------------------------------------------------------- /example/images/dialog_plus_custom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbmiranda/flutter_plus/HEAD/example/images/dialog_plus_custom.png -------------------------------------------------------------------------------- /example/images/text_field_plus_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbmiranda/flutter_plus/HEAD/example/images/text_field_plus_1.png -------------------------------------------------------------------------------- /example/images/text_field_plus_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbmiranda/flutter_plus/HEAD/example/images/text_field_plus_2.png -------------------------------------------------------------------------------- /example/images/text_field_plus_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbmiranda/flutter_plus/HEAD/example/images/text_field_plus_3.png -------------------------------------------------------------------------------- /example/images/dialog_plus_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbmiranda/flutter_plus/HEAD/example/images/dialog_plus_default.png -------------------------------------------------------------------------------- /example/images/snack_bar_plus_custom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbmiranda/flutter_plus/HEAD/example/images/snack_bar_plus_custom.png -------------------------------------------------------------------------------- /example/images/snack_bar_plus_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbmiranda/flutter_plus/HEAD/example/images/snack_bar_plus_default.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/gbmiranda/flutter_plus/HEAD/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/gbmiranda/flutter_plus/HEAD/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/gbmiranda/flutter_plus/HEAD/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/gbmiranda/flutter_plus/HEAD/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/gbmiranda/flutter_plus/HEAD/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbmiranda/flutter_plus/HEAD/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/gbmiranda/flutter_plus/HEAD/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/gbmiranda/flutter_plus/HEAD/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/gbmiranda/flutter_plus/HEAD/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/gbmiranda/flutter_plus/HEAD/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/gbmiranda/flutter_plus/HEAD/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/gbmiranda/flutter_plus/HEAD/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/gbmiranda/flutter_plus/HEAD/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/gbmiranda/flutter_plus/HEAD/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/gbmiranda/flutter_plus/HEAD/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/gbmiranda/flutter_plus/HEAD/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/gbmiranda/flutter_plus/HEAD/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/gbmiranda/flutter_plus/HEAD/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/gbmiranda/flutter_plus/HEAD/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/gbmiranda/flutter_plus/HEAD/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbmiranda/flutter_plus/HEAD/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/gbmiranda/flutter_plus/HEAD/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/gbmiranda/flutter_plus/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /example/android/app/src/main/kotlin/com/example/example/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.example 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /example/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'flutter_plus_example.dart'; 3 | 4 | void main() { 5 | WidgetsFlutterBinding.ensureInitialized(); 6 | runApp(FlutterPlusExample()); 7 | } 8 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /lib/src/widgets/widgets_export_plus.dart: -------------------------------------------------------------------------------- 1 | export 'src/button_plus.dart'; 2 | export 'src/container_plus.dart'; 3 | export 'src/flutter_app_plus.dart'; 4 | export 'src/rich_text_plus.dart'; 5 | export 'src/text_field_plus.dart'; 6 | export 'src/text_plus.dart'; 7 | -------------------------------------------------------------------------------- /lib/src/extensions/extensions_export_plus.dart: -------------------------------------------------------------------------------- 1 | export 'src/date_extension_plus.dart'; 2 | export 'src/duration_extension_plus.dart'; 3 | export 'src/file_extension_plus.dart'; 4 | export 'src/num_extension_plus.dart'; 5 | export 'src/string_exntension_plus.dart'; 6 | -------------------------------------------------------------------------------- /lib/src/utils/utils_export_plus.dart: -------------------------------------------------------------------------------- 1 | export 'src/bottom_sheet_plus.dart'; 2 | export 'src/dialog_plus.dart'; 3 | export 'src/local_storage_plus.dart'; 4 | export 'src/navigator_plus.dart'; 5 | export 'src/snack_bar_plus.dart'; 6 | export 'src/utils_plus.dart'; 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: fba99f6cf9a14512e461e3122c8ddfaa25394e89 8 | channel: stable 9 | 10 | project_type: package 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: 84f3d28555368a70270e9ac8390a9441df95e752 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /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/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /example/ios/Runner/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 | -------------------------------------------------------------------------------- /lib/src/components/components_export_plus.dart: -------------------------------------------------------------------------------- 1 | export 'src/border_plus.dart'; 2 | export 'src/gradient_plus.dart'; 3 | export 'src/inner_shadow_plus.dart'; 4 | // export 'src/inner_shadow_render_plus.dart'; 5 | export 'src/radius_plus.dart'; 6 | export 'src/shadow_plus.dart'; 7 | export 'src/skeleton_plus.dart'; 8 | // export 'src/skeleton_render_plus.dart'; 9 | export 'src/text_decoration_plus.dart'; 10 | // export 'src/text_field_mask_plus.dart'; 11 | // export 'src/text_rich_pattern_plus.dart'; 12 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # example 2 | 3 | A new Flutter project. 4 | 5 | ## Getting Started 6 | 7 | This project is a starting point for a Flutter application. 8 | 9 | A few resources to get you started if this is your first Flutter project: 10 | 11 | - [Lab: Write your first Flutter app](https://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 | -------------------------------------------------------------------------------- /lib/src/components/src/inner_shadow_plus.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class InnerShadowPlus { 4 | /// InnerShadow color 5 | final Color color; 6 | 7 | /// InnerShadow color opacity -> 0.0 to 1.0 8 | final double? opacity; 9 | 10 | /// InnerShadow blur 11 | final double blur; 12 | 13 | /// InnerShadow x position 14 | final double moveRight; 15 | 16 | /// InnerShadow y position 17 | final double moveDown; 18 | 19 | InnerShadowPlus({ 20 | this.color = Colors.black, 21 | this.blur = 4, 22 | this.moveRight = 0, 23 | this.moveDown = 0, 24 | this.opacity, 25 | }); 26 | } 27 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [1.0.0] - 27/04/2021 2 | * Improvements; 3 | ## [0.0.9] - 15/04/2021 4 | * Migrate to null safety by @pythonhubpy; 5 | ## [0.0.8] - 30/03/2021 6 | * Improvements; 7 | ## [0.0.7] - 01/03/2021 8 | * Improvements; 9 | ## [0.0.6] - 06/12/2020 10 | * Improvements; 11 | ## [0.0.5] - 04/12/2020 12 | * Web 13 | * Code and Documentation improvements; 14 | ## [0.0.4] - 27/11/2020 15 | * Pedantic analyze; 16 | * Code and Documentation improvements; 17 | ## [0.0.3] - 27/11/2020 18 | * Code and Documentation improvements; 19 | ## [0.0.2] - 26/11/2020 20 | * Code and Documentation improvements; 21 | ## [0.0.1] - 13/10/2020 22 | * First release; 23 | -------------------------------------------------------------------------------- /lib/src/utils/src/utils_plus.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | final utilsPlus = UtilsPlus._instance; 4 | 5 | class UtilsPlus { 6 | static final _instance = UtilsPlus._(); 7 | UtilsPlus._(); 8 | 9 | /// Closes the keyboard if it is open 10 | void closeKeyboard() { 11 | FocusManager.instance.primaryFocus!.unfocus(); 12 | } 13 | 14 | /// Turns a hexadecimal String to Color 15 | Color colorHex(String hex) { 16 | return Color(int.parse("0xFF${hex.replaceAll('#', '')}")); 17 | } 18 | 19 | /// Turns a Color to String hexadecimal 20 | String colorToHex(Color color) { 21 | return color.value.toRadixString(16); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/src/components/src/shadow_plus.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class ShadowPlus { 4 | /// Shadow color 5 | final Color color; 6 | 7 | /// Shadow color opacity -> 0.0 to 1.0 8 | final double? opacity; 9 | 10 | /// Shadow blur 11 | final double blur; 12 | 13 | /// Shadow spread 14 | final double spread; 15 | 16 | /// Shadow x position 17 | final double moveRight; 18 | 19 | /// Shadow y position 20 | final double moveDown; 21 | 22 | ShadowPlus({ 23 | this.color = Colors.black, 24 | this.blur = 5, 25 | this.spread = 1, 26 | this.moveRight = 0, 27 | this.moveDown = 0, 28 | this.opacity, 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /example/web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example", 3 | "short_name": "example", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A new Flutter project.", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /example/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 | -------------------------------------------------------------------------------- /lib/src/components/src/text_decoration_plus.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class TextDecorationPlus { 4 | /// Native Flutter TextDecoration 5 | final TextDecoration textDecoration; 6 | 7 | /// TextDecorationPlus color 8 | final Color color; 9 | 10 | /// Native Flutter TextDecorationStyle 11 | final TextDecorationStyle decorationStyle; 12 | 13 | /// TextDecorationPlus decorationThickness 14 | final double decorationThickness; 15 | 16 | TextDecorationPlus({ 17 | this.textDecoration = TextDecoration.none, 18 | this.color = Colors.black, 19 | this.decorationStyle = TextDecorationStyle.solid, 20 | this.decorationThickness = 1.0, 21 | }); 22 | } 23 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_plus 2 | description: Create customized Containers/Buttons/TextFields/Texts/RichTexts in a few lines. Navigate between Screens and open BottomSheets/Dialogs/Snackbars without context and more! 3 | version: 1.0.1 4 | homepage: https://github.com/gbmiranda/flutter_plus.git 5 | repository: https://github.com/gbmiranda/flutter_plus.git 6 | issue_tracker: https://github.com/gbmiranda/flutter_plus/issues 7 | 8 | environment: 9 | sdk: '>=2.12.0 <3.0.0' 10 | 11 | dependencies: 12 | flutter: 13 | sdk: flutter 14 | intl: ^0.17.0 15 | diacritic: ^0.1.3 16 | shared_preferences: ^2.0.6 17 | path: ^1.8.0 18 | 19 | dev_dependencies: 20 | flutter_test: 21 | sdk: flutter 22 | pedantic: ^1.11.1 23 | 24 | flutter: -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /lib/src/components/src/border_plus.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class BorderPlus { 4 | /// Border color 5 | final Color color; 6 | 7 | /// Border width 8 | final double width; 9 | 10 | /// Border style 11 | final BorderStyle style; 12 | 13 | /// BorderPlus constructor 14 | BorderPlus({ 15 | this.color = Colors.black, 16 | this.width = 1, 17 | this.style = BorderStyle.solid, 18 | }); 19 | 20 | /// Transform BorderPlus to native Flutter Border 21 | Border get toBorder { 22 | return Border.all( 23 | style: style, 24 | color: color, 25 | width: width, 26 | ); 27 | } 28 | 29 | /// Transform BorderPlus to native Flutter BorderSide 30 | BorderSide get toBorderSide { 31 | return BorderSide( 32 | style: style, 33 | color: color, 34 | width: width, 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /example/ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Flutter (1.0.0) 3 | - shared_preferences (0.0.1): 4 | - Flutter 5 | - url_launcher (0.0.1): 6 | - Flutter 7 | 8 | DEPENDENCIES: 9 | - Flutter (from `Flutter`) 10 | - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) 11 | - url_launcher (from `.symlinks/plugins/url_launcher/ios`) 12 | 13 | EXTERNAL SOURCES: 14 | Flutter: 15 | :path: Flutter 16 | shared_preferences: 17 | :path: ".symlinks/plugins/shared_preferences/ios" 18 | url_launcher: 19 | :path: ".symlinks/plugins/url_launcher/ios" 20 | 21 | SPEC CHECKSUMS: 22 | Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c 23 | shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d 24 | url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef 25 | 26 | PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c 27 | 28 | COCOAPODS: 1.10.1 29 | -------------------------------------------------------------------------------- /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 | 10.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/lib/src/screens/navigator_plus_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_plus/flutter_plus.dart'; 3 | 4 | class NavigatorPlusScreen extends StatelessWidget { 5 | @override 6 | Widget build(BuildContext context) { 7 | return Scaffold( 8 | appBar: AppBar( 9 | title: TextPlus( 10 | 'NavigatorPlus Example', 11 | color: Colors.white, 12 | fontWeight: FontWeight.bold, 13 | ), 14 | backgroundColor: Colors.red, 15 | ), 16 | body: _buildBody(), 17 | ); 18 | } 19 | 20 | Widget _buildBody() { 21 | return SingleChildScrollView( 22 | padding: EdgeInsets.all(24), 23 | child: Center( 24 | child: Column( 25 | mainAxisAlignment: MainAxisAlignment.center, 26 | crossAxisAlignment: CrossAxisAlignment.center, 27 | children: [], 28 | ), 29 | ), 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /example/lib/flutter_plus_example.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_plus/flutter_plus.dart'; 3 | 4 | import 'src/screens/home_screen.dart'; 5 | 6 | class FlutterPlusExample extends StatefulWidget { 7 | @override 8 | _FlutterPlusExampleState createState() => _FlutterPlusExampleState(); 9 | } 10 | 11 | class _FlutterPlusExampleState extends State { 12 | @override 13 | Widget build(BuildContext context) { 14 | // Using FlutterAppPlus 15 | return FlutterAppPlus( 16 | title: 'Flutter Plus Example', 17 | home: HomeScreen(), 18 | ); 19 | 20 | // Using MaterialApp 21 | // MaterialApp( 22 | // title: 'Flutter Plus Example', 23 | // navigatorKey: navigatorPlus.key, 24 | // builder: (context, child) { 25 | // return Scaffold( 26 | // key: snackBarPlus.scaffoldKey, 27 | // body: child, 28 | // ); 29 | // }, 30 | // ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /lib/flutter_plus.dart: -------------------------------------------------------------------------------- 1 | library flutter_plus; 2 | 3 | import 'src/utils/utils_export_plus.dart'; 4 | 5 | export 'package:flutter_plus/src/components/components_export_plus.dart'; 6 | export 'package:flutter_plus/src/extensions/extensions_export_plus.dart'; 7 | export 'package:flutter_plus/src/utils/utils_export_plus.dart'; 8 | export 'package:flutter_plus/src/widgets/widgets_export_plus.dart'; 9 | 10 | class FlutterPlus { 11 | FlutterPlus._(); 12 | 13 | /// Access FlutterPlus UtilsPlus 14 | static UtilsPlus utils = utilsPlus; 15 | 16 | /// Access FlutterPlus LocalStoragePlus 17 | static LocalStoragePlus localStorage = localStoragePlus; 18 | 19 | /// Access FlutterPlus NavigatorPlus 20 | static NavigatorPlus navigator = navigatorPlus; 21 | 22 | /// Access FlutterPlus SnackBarPlus 23 | static SnackBarPlus snackBar = snackBarPlus; 24 | 25 | /// Access FlutterPlus DialogPlus 26 | static DialogPlus dialog = dialogPlus; 27 | 28 | /// Access FlutterPlus BottomSheetPlus 29 | static BottomSheetPlus bottomSheet = bottomSheetPlus; 30 | } 31 | -------------------------------------------------------------------------------- /lib/src/extensions/src/file_extension_plus.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:io'; 3 | import 'package:path/path.dart' as path; 4 | 5 | extension FileExtensionPlus on File { 6 | /// Convert File to base64 sync 7 | String? get base64Sync { 8 | if (this == null) { 9 | return null; 10 | } else { 11 | List fileBytes = readAsBytesSync(); 12 | return base64Encode(fileBytes); 13 | } 14 | } 15 | 16 | /// Convert File to base64 async 17 | Future? get base64Async { 18 | if (this == null) { 19 | return null; 20 | } else { 21 | return readAsBytes().then(base64Encode); 22 | } 23 | } 24 | 25 | /// Get File complete name 26 | String get fileName { 27 | return path.basename(this.path); 28 | } 29 | 30 | /// Get File name without extension 31 | String get fileNameWithoutExtension { 32 | return path.basenameWithoutExtension(this.path); 33 | } 34 | 35 | /// Get File extension 36 | String get fileExtension { 37 | return path.extension(this.path); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Gabriel Braga 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /lib/src/components/src/skeleton_plus.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class SkeletonPlus { 4 | /// Skeleton animation enabled or disabled -> true or false 5 | final bool enabled; 6 | 7 | /// Skeleton show widget shadows -> true or false 8 | final bool showShadows; 9 | 10 | /// Skeleton show widget borders -> true or false 11 | final bool showBorders; 12 | 13 | /// Skeleton base color 14 | final Color? baseColor; 15 | 16 | /// Skeleton animated color 17 | final Color? highlightColor; 18 | 19 | /// Skeleton animation duration 20 | final Duration? duration; 21 | 22 | /// Custom Skeleton animation 23 | SkeletonPlus.custom({ 24 | required this.enabled, 25 | this.baseColor, 26 | this.highlightColor, 27 | this.duration, 28 | this.showShadows = false, 29 | this.showBorders = false, 30 | }); 31 | 32 | /// Default Skeleton animation 33 | SkeletonPlus.automatic({required this.enabled}) 34 | : baseColor = null, 35 | highlightColor = null, 36 | duration = Duration(milliseconds: 1500), 37 | showShadows = false, 38 | showBorders = false; 39 | } 40 | -------------------------------------------------------------------------------- /example/lib/src/widgets/custom_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_plus/flutter_plus.dart'; 3 | 4 | class CustomWidget extends StatelessWidget { 5 | @override 6 | Widget build(BuildContext context) { 7 | return Container( 8 | padding: EdgeInsets.all(24), 9 | child: Column( 10 | mainAxisAlignment: MainAxisAlignment.center, 11 | children: [ 12 | TextPlus( 13 | 'FlutterPlus', 14 | color: Colors.black, 15 | fontWeight: FontWeight.bold, 16 | fontSize: 20, 17 | ), 18 | ButtonPlus( 19 | margin: EdgeInsets.only(top: 16), 20 | isCenter: true, 21 | color: Colors.red, 22 | radius: RadiusPlus.all(12), 23 | child: TextPlus( 24 | 'CLOSE', 25 | color: Colors.white, 26 | fontWeight: FontWeight.bold, 27 | fontSize: 16, 28 | ), 29 | onPressed: () { 30 | navigatorPlus.back(); 31 | }, 32 | ), 33 | ], 34 | ), 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lib/src/extensions/src/duration_extension_plus.dart: -------------------------------------------------------------------------------- 1 | extension DurationExtensionPlus on Duration { 2 | /// Duration in months 3 | int get months { 4 | return inDays.remainder(60).toInt(); 5 | } 6 | 7 | /// Duration in days 8 | int get days { 9 | return inDays.toInt(); 10 | } 11 | 12 | /// Duration in hours 13 | int get hours { 14 | return inHours.remainder(60).toInt(); 15 | } 16 | 17 | /// Duration in hours formatted 18 | String get hoursStr { 19 | return hours.toString().padLeft(2, "0"); 20 | } 21 | 22 | /// Duration in minutes 23 | int get minutes { 24 | return inMinutes.remainder(60).toInt(); 25 | } 26 | 27 | /// Duration in minutes formatted 28 | String get minutesStr { 29 | return minutes.toString().padLeft(2, "0"); 30 | } 31 | 32 | /// Duration in seconds 33 | int get seconds { 34 | return inSeconds.remainder(60).toInt(); 35 | } 36 | 37 | /// Duration in seconds formatted 38 | String get secondsStr { 39 | return seconds.toString().padLeft(2, "0"); 40 | } 41 | 42 | /// Duration formatted 43 | String get formattedDuration { 44 | return '$hoursStr:$minutesStr:$secondsStr'; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /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/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | example 30 | 31 | 32 | 33 | 36 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | example 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /lib/src/components/src/radius_plus.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | 3 | class RadiusPlus { 4 | /// Radius value for all corners 5 | final double? all; 6 | 7 | /// Radius value for topLeft corner 8 | final double? topLeft; 9 | 10 | /// Radius value for topRight corner 11 | final double? topRight; 12 | 13 | /// Radius value for bottomLeft corner 14 | final double? bottomLeft; 15 | 16 | /// Radius value for bottomRight corner 17 | final double? bottomRight; 18 | 19 | /// Radius to all corners 20 | RadiusPlus.all(this.all) 21 | : topLeft = all, 22 | topRight = all, 23 | bottomLeft = all, 24 | bottomRight = all; 25 | 26 | /// Radius to specific corner 27 | RadiusPlus.only({ 28 | this.topLeft, 29 | this.topRight, 30 | this.bottomLeft, 31 | this.bottomRight, 32 | }) : all = null; 33 | 34 | /// Radius to all top corners 35 | RadiusPlus.top(double radiusTop) 36 | : all = null, 37 | topLeft = radiusTop, 38 | topRight = radiusTop, 39 | bottomLeft = null, 40 | bottomRight = null; 41 | 42 | /// Radius to all bottom corners 43 | RadiusPlus.bottom(double radiusBottom) 44 | : all = null, 45 | topLeft = null, 46 | topRight = null, 47 | bottomLeft = radiusBottom, 48 | bottomRight = radiusBottom; 49 | 50 | /// Transform RadiusPlus to native Flutter BorderRadius 51 | BorderRadius get toBorderRadius { 52 | return BorderRadius.only( 53 | topLeft: Radius.circular(topLeft ?? 0), 54 | topRight: Radius.circular(topRight ?? 0), 55 | bottomLeft: Radius.circular(bottomLeft ?? 0), 56 | bottomRight: Radius.circular(bottomRight ?? 0), 57 | ); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /lib/src/components/src/inner_shadow_render_plus.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter/rendering.dart'; 4 | 5 | class InnerShadowRenderPlus extends SingleChildRenderObjectWidget { 6 | const InnerShadowRenderPlus({ 7 | Key? key, 8 | this.shadows = const [], 9 | Widget? child, 10 | }) : super(key: key, child: child); 11 | 12 | final List shadows; 13 | 14 | @override 15 | RenderObject createRenderObject(BuildContext context) { 16 | final renderObject = _RenderInnerShadow(); 17 | updateRenderObject(context, renderObject); 18 | return renderObject; 19 | } 20 | 21 | @override 22 | void updateRenderObject( 23 | BuildContext context, _RenderInnerShadow renderObject) { 24 | renderObject.shadows = shadows; 25 | } 26 | } 27 | 28 | class _RenderInnerShadow extends RenderProxyBox { 29 | late List shadows; 30 | 31 | @override 32 | void paint(PaintingContext context, Offset offset) { 33 | if (child == null) return; 34 | final bounds = offset & size; 35 | 36 | context.canvas.saveLayer(bounds, Paint()); 37 | context.paintChild(child!, offset); 38 | 39 | for (final shadow in shadows) { 40 | final shadowRect = bounds.inflate(shadow.blurSigma); 41 | final shadowPaint = Paint() 42 | ..blendMode = BlendMode.srcATop 43 | ..colorFilter = ColorFilter.mode(shadow.color, BlendMode.srcOut) 44 | ..imageFilter = ImageFilter.blur( 45 | sigmaX: shadow.blurSigma, 46 | sigmaY: shadow.blurSigma, 47 | ); 48 | context.canvas 49 | ..saveLayer(shadowRect, shadowPaint) 50 | ..translate(shadow.offset.dx, shadow.offset.dy); 51 | context.paintChild(child!, offset); 52 | context.canvas.restore(); 53 | } 54 | 55 | context.canvas.restore(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | .dart_tool/ 26 | .flutter-plugins 27 | .flutter-plugins-dependencies 28 | .packages 29 | .pub-cache/ 30 | .pub/ 31 | build/ 32 | 33 | # Android related 34 | **/android/**/gradle-wrapper.jar 35 | **/android/.gradle 36 | **/android/captures/ 37 | **/android/gradlew 38 | **/android/gradlew.bat 39 | **/android/local.properties 40 | **/android/**/GeneratedPluginRegistrant.java 41 | 42 | # iOS/XCode related 43 | **/ios/**/*.mode1v3 44 | **/ios/**/*.mode2v3 45 | **/ios/**/*.moved-aside 46 | **/ios/**/*.pbxuser 47 | **/ios/**/*.perspectivev3 48 | **/ios/**/*sync/ 49 | **/ios/**/.sconsign.dblite 50 | **/ios/**/.tags* 51 | **/ios/**/.vagrant/ 52 | **/ios/**/DerivedData/ 53 | **/ios/**/Icon? 54 | **/ios/**/Pods/ 55 | **/ios/**/.symlinks/ 56 | **/ios/**/profile 57 | **/ios/**/xcuserdata 58 | **/ios/.generated/ 59 | **/ios/Flutter/App.framework 60 | **/ios/Flutter/Flutter.framework 61 | **/ios/Flutter/Flutter.podspec 62 | **/ios/Flutter/Generated.xcconfig 63 | **/ios/Flutter/app.flx 64 | **/ios/Flutter/app.zip 65 | **/ios/Flutter/flutter_assets/ 66 | **/ios/Flutter/flutter_export_environment.sh 67 | **/ios/ServiceDefinitions.json 68 | **/ios/Runner/GeneratedPluginRegistrant.* 69 | 70 | # Exceptions to above rules. 71 | !**/ios/**/default.mode1v3 72 | !**/ios/**/default.mode2v3 73 | !**/ios/**/default.pbxuser 74 | !**/ios/**/default.perspectivev3 75 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 76 | -------------------------------------------------------------------------------- /example/lib/src/screens/rich_text_plus_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_plus/flutter_plus.dart'; 3 | 4 | class RichTextPlusScreen extends StatelessWidget { 5 | @override 6 | Widget build(BuildContext context) { 7 | return Scaffold( 8 | appBar: AppBar( 9 | title: TextPlus( 10 | 'RichTextPlus Example', 11 | color: Colors.white, 12 | fontWeight: FontWeight.bold, 13 | ), 14 | backgroundColor: Colors.red, 15 | ), 16 | body: _buildBody(), 17 | ); 18 | } 19 | 20 | Widget _buildBody() { 21 | return SingleChildScrollView( 22 | padding: EdgeInsets.all(24), 23 | child: Center( 24 | child: Column( 25 | mainAxisAlignment: MainAxisAlignment.center, 26 | crossAxisAlignment: CrossAxisAlignment.center, 27 | children: [ 28 | _buildExample(), 29 | ], 30 | ), 31 | ), 32 | ); 33 | } 34 | 35 | Widget _buildExample() { 36 | return RichTextPlus( 37 | texts: [ 38 | TextPlus( 39 | 'Flutter ', 40 | color: Colors.black, 41 | fontWeight: FontWeight.normal, 42 | fontSize: 30, 43 | ), 44 | TextPlus( 45 | 'Plus ', 46 | color: Colors.red, 47 | fontWeight: FontWeight.bold, 48 | fontSize: 30, 49 | ), 50 | TextPlus( 51 | '!', 52 | color: Colors.blue, 53 | fontWeight: FontWeight.bold, 54 | fontSize: 30, 55 | ), 56 | TextPlus( 57 | '!', 58 | color: Colors.green, 59 | fontWeight: FontWeight.bold, 60 | fontSize: 30, 61 | ), 62 | TextPlus( 63 | '!', 64 | color: Colors.orange, 65 | fontWeight: FontWeight.bold, 66 | fontSize: 30, 67 | ), 68 | ], 69 | ); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /lib/src/widgets/src/rich_text_plus.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:intl/intl.dart'; 3 | 4 | import '../../../flutter_plus.dart'; 5 | 6 | class RichTextPlus extends StatelessWidget { 7 | /* 8 | Todo 9 | urls 10 | phones 11 | dates 12 | */ 13 | 14 | /// RichTextPlus texts 15 | final List? texts; 16 | 17 | /// RichTextPlus maxLines 18 | final int? maxLines; 19 | 20 | /// RichTextPlus inside Center widget 21 | final bool isCenter; 22 | 23 | /// RichTextPlus inside Expanded widget 24 | final bool isExpanded; 25 | 26 | final TextOverflow? overflow; 27 | final bool? softWrap; 28 | final TextAlign? textAlign; 29 | 30 | RichTextPlus({ 31 | Key? key, 32 | this.maxLines, 33 | // custom 34 | this.isCenter = false, 35 | this.isExpanded = false, 36 | this.texts, 37 | this.overflow, 38 | this.softWrap = true, 39 | this.textAlign, 40 | // this.mainTextStyleX, 41 | }) : super(key: key); 42 | 43 | @override 44 | Widget build(BuildContext context) { 45 | var richTextPlus = _buildRichTextPlus(); 46 | 47 | if (isCenter == true) { 48 | richTextPlus = Center( 49 | child: richTextPlus, 50 | ); 51 | } 52 | 53 | if (isExpanded == true) { 54 | richTextPlus = Expanded( 55 | child: richTextPlus, 56 | ); 57 | } 58 | return richTextPlus; 59 | } 60 | 61 | Widget _buildRichTextPlus() { 62 | return RichText( 63 | key: key, 64 | maxLines: maxLines, 65 | overflow: overflow ?? TextOverflow.visible, 66 | softWrap: softWrap!, 67 | textAlign: textAlign ?? TextAlign.start, 68 | text: TextSpan( 69 | text: '', 70 | children: texts! 71 | .map( 72 | (richTextPlus) => TextSpan( 73 | text: richTextPlus.text, 74 | style: richTextPlus.textStyle, 75 | ), 76 | ) 77 | .toList(), 78 | ), 79 | ); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /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.example.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 | -------------------------------------------------------------------------------- /lib/src/extensions/src/date_extension_plus.dart: -------------------------------------------------------------------------------- 1 | import 'package:intl/intl.dart'; 2 | 3 | extension DateExtensionPlus on DateTime { 4 | /// Format DateTime to String 5 | String? format(String format) { 6 | if (this == null) { 7 | return null; 8 | } else { 9 | return DateFormat(format).format(this); 10 | } 11 | } 12 | 13 | /// Number of days in month 14 | int get daysOfMonth { 15 | if (this == null) { 16 | { 17 | return -1; 18 | } 19 | } else { 20 | final beginningNextMonth = (month < 12) 21 | ? DateTime(year, month + 1, 1) 22 | : DateTime(year + 1, 1, 1); 23 | return beginningNextMonth.subtract(Duration(days: 1)).day; 24 | } 25 | } 26 | 27 | /// Number of days in year 28 | int get daysOfYear { 29 | if (this == null) { 30 | return -1; 31 | } else { 32 | final firstMonth = DateTime(year, 1, 1); 33 | final lastMonth = DateTime(year, 12, 31); 34 | return firstMonth.difference(lastMonth).inDays; 35 | } 36 | } 37 | 38 | /// Checks whether it is the current day 39 | bool get isToday { 40 | if (this == null) { 41 | return false; 42 | } else { 43 | final now = DateTime.now(); 44 | final today = DateTime(now.year, now.month, now.day); 45 | final dateCheck = DateTime(year, month, day); 46 | return today == dateCheck; 47 | } 48 | } 49 | 50 | /// Month name 51 | String? get monthName { 52 | return format('MMMM'); 53 | } 54 | 55 | /// Month name sort 56 | String? get monthNameSort { 57 | return format('MMM'); 58 | } 59 | 60 | /// Week name 61 | String? get weekName { 62 | return format('EEEE'); 63 | } 64 | 65 | /// Week name sort 66 | String? get weekNameSort { 67 | return format('EEE'); 68 | } 69 | 70 | /// Checks if two dates are equal 71 | bool sameDay(DateTime compareDate) { 72 | if (this == null) { 73 | return false; 74 | } else { 75 | return day == compareDate.day && 76 | month == compareDate.month && 77 | year == compareDate.year; 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /lib/src/components/src/skeleton_render_plus.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import '../../../flutter_plus.dart'; 4 | 5 | class SkeletonRenderPlus extends StatefulWidget { 6 | final SkeletonPlus? skeletonPlus; 7 | SkeletonRenderPlus({required this.skeletonPlus}); 8 | 9 | @override 10 | _SkeletonRenderPlusState createState() => _SkeletonRenderPlusState(); 11 | } 12 | 13 | class _SkeletonRenderPlusState extends State 14 | with SingleTickerProviderStateMixin { 15 | late AnimationController _controller; 16 | Animation? _gradientPosition; 17 | double get _gradientPositionValue { 18 | if (_gradientPosition != null && _gradientPosition!.value is double) { 19 | return _gradientPosition!.value as double; 20 | } else { 21 | return 0; 22 | } 23 | } 24 | 25 | @override 26 | void initState() { 27 | _controller = AnimationController( 28 | duration: widget.skeletonPlus!.duration ?? Duration(milliseconds: 1500), 29 | vsync: this, 30 | ); 31 | _gradientPosition = Tween( 32 | begin: -30, 33 | end: 10, 34 | ).animate( 35 | CurvedAnimation(parent: _controller, curve: Curves.linear), 36 | )..addListener( 37 | () { 38 | setState(() {}); 39 | }, 40 | ); 41 | 42 | _controller.repeat(); 43 | 44 | super.initState(); 45 | } 46 | 47 | @override 48 | void dispose() { 49 | _controller.stop(); 50 | _controller.dispose(); 51 | super.dispose(); 52 | } 53 | 54 | @override 55 | Widget build(BuildContext context) { 56 | return Container( 57 | decoration: BoxDecoration( 58 | gradient: LinearGradient( 59 | begin: Alignment(_gradientPositionValue, 0), 60 | end: Alignment(2, 0), 61 | colors: [ 62 | widget.skeletonPlus!.baseColor ?? utilsPlus.colorHex('E0E0E0'), 63 | widget.skeletonPlus!.highlightColor ?? utilsPlus.colorHex('F0F1F1'), 64 | widget.skeletonPlus!.baseColor ?? utilsPlus.colorHex('E0E0E0'), 65 | ], 66 | stops: [ 67 | 0.2, 68 | 0.6, 69 | 0.9, 70 | ], 71 | ), 72 | ), 73 | ); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /lib/src/utils/src/local_storage_plus.dart: -------------------------------------------------------------------------------- 1 | import 'package:shared_preferences/shared_preferences.dart'; 2 | 3 | final localStoragePlus = LocalStoragePlus._instance; 4 | 5 | class LocalStoragePlus { 6 | static final _instance = LocalStoragePlus._(); 7 | LocalStoragePlus._(); 8 | 9 | /// Save data with custom key 10 | Future write(String key, dynamic data) async { 11 | return SharedPreferences.getInstance().then((sharedPreferences) { 12 | if (data is bool) { 13 | sharedPreferences.setBool(key, data); 14 | } else if (data is String) { 15 | sharedPreferences.setString(key, data); 16 | } else if (data is int) { 17 | sharedPreferences.setInt(key, data); 18 | } else if (data is double) { 19 | sharedPreferences.setDouble(key, data); 20 | } else if (data is List) { 21 | sharedPreferences.setStringList(key, data); 22 | } else { 23 | print('FlutterPlusUtils.write -> INVALID TYPE'); 24 | } 25 | }).catchError((error) { 26 | print('FlutterPlusUtils.write -> $error'); 27 | }); 28 | } 29 | 30 | /// Get data with custom key 31 | Future read(String key) { 32 | return SharedPreferences.getInstance().then((sharedPreferences) { 33 | return sharedPreferences.get(key); 34 | }).catchError((error) { 35 | print('FlutterPlusUtils.read -> $error'); 36 | }); 37 | } 38 | 39 | /// Delete data with custom key 40 | Future delete(String key) async { 41 | return SharedPreferences.getInstance().then((sharedPreferences) { 42 | return sharedPreferences.remove(key); 43 | }).catchError((error) { 44 | print('FlutterPlusUtils.delete -> $error'); 45 | }); 46 | } 47 | 48 | /// Clear all local data 49 | Future clear() async { 50 | return SharedPreferences.getInstance().then((sharedPreferences) { 51 | return sharedPreferences.clear(); 52 | }).catchError((error) { 53 | print('FlutterPlusUtils.clear -> $error'); 54 | }); 55 | } 56 | 57 | /// Check if key exists 58 | Future containsKey(String key) async { 59 | return SharedPreferences.getInstance().then((sharedPreferences) { 60 | return sharedPreferences.containsKey(key); 61 | }).catchError((error) { 62 | print('FlutterPlusUtils.containsKey -> $error'); 63 | }); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /lib/src/components/src/gradient_plus.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class GradientPlus { 4 | /// Gradient colors 5 | final List colors; 6 | 7 | /// Gradient colors stops 8 | final List? stops; 9 | 10 | /// Gradient tileMode 11 | final TileMode tileMode; 12 | 13 | LinearGradient? _linearGradient; 14 | 15 | /// Gradient linear mode 16 | GradientPlus.linear({ 17 | required this.colors, 18 | this.stops, 19 | this.tileMode = TileMode.clamp, 20 | Alignment begin = Alignment.centerLeft, 21 | Alignment end = Alignment.centerRight, 22 | }) { 23 | _linearGradient = LinearGradient( 24 | colors: colors, 25 | begin: begin, 26 | end: end, 27 | stops: stops, 28 | tileMode: tileMode, 29 | ); 30 | } 31 | 32 | RadialGradient? _radialGradient; 33 | 34 | /// Gradient radial mode 35 | GradientPlus.radial({ 36 | required this.colors, 37 | this.stops, 38 | this.tileMode = TileMode.clamp, 39 | Alignment center = Alignment.center, 40 | Alignment focal = Alignment.center, 41 | double focalRadius = 0.0, 42 | double radius = 0.0, 43 | }) { 44 | _radialGradient = RadialGradient( 45 | colors: colors, 46 | center: center, 47 | focal: focal, 48 | focalRadius: focalRadius, 49 | radius: radius, 50 | stops: stops, 51 | tileMode: tileMode, 52 | ); 53 | } 54 | 55 | SweepGradient? _sweepGradient; 56 | 57 | /// Gradient sweep mode 58 | GradientPlus.sweep({ 59 | required this.colors, 60 | this.stops, 61 | this.tileMode = TileMode.clamp, 62 | Alignment center = Alignment.center, 63 | double startAngle = 0.0, 64 | double endAngle = 0.0, 65 | }) { 66 | _sweepGradient = SweepGradient( 67 | colors: colors, 68 | center: center, 69 | endAngle: endAngle, 70 | startAngle: startAngle, 71 | stops: stops, 72 | tileMode: tileMode, 73 | ); 74 | } 75 | 76 | /// Transform GradientPlus to native Flutter Gradient 77 | Gradient? get toGradient { 78 | if (_linearGradient != null) { 79 | return _linearGradient; 80 | } else if (_radialGradient != null) { 81 | return _radialGradient; 82 | } else if (_sweepGradient != null) { 83 | return _sweepGradient; 84 | } else { 85 | return null; 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /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/lib/src/screens/text_plus_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_plus/flutter_plus.dart'; 3 | 4 | class TextPlusScreen extends StatelessWidget { 5 | @override 6 | Widget build(BuildContext context) { 7 | return Scaffold( 8 | appBar: AppBar( 9 | title: TextPlus( 10 | 'TextPlus Example', 11 | color: Colors.white, 12 | fontWeight: FontWeight.bold, 13 | ), 14 | backgroundColor: Colors.red, 15 | ), 16 | body: _buildBody(), 17 | ); 18 | } 19 | 20 | Widget _buildBody() { 21 | return SingleChildScrollView( 22 | padding: EdgeInsets.all(24), 23 | child: Center( 24 | child: Column( 25 | mainAxisAlignment: MainAxisAlignment.center, 26 | crossAxisAlignment: CrossAxisAlignment.center, 27 | children: [ 28 | _buildExample1(), 29 | _buildExample2(), 30 | _buildExample3(), 31 | ], 32 | ), 33 | ), 34 | ); 35 | } 36 | 37 | Widget _buildExample1() { 38 | return TextPlus( 39 | 'Exemplo 1', 40 | padding: EdgeInsets.all(16), 41 | backgroundColor: Colors.red, 42 | color: Colors.white, 43 | fontSize: 20, 44 | fontWeight: FontWeight.w700, 45 | letterSpacing: 2, 46 | wordSpacing: 20, 47 | maxLines: 1, 48 | textOverflow: TextOverflow.ellipsis, 49 | ); 50 | } 51 | 52 | Widget _buildExample2() { 53 | return TextPlus( 54 | 'Exemplo 2', 55 | color: Colors.white, 56 | fontSize: 20, 57 | margin: EdgeInsets.only(top: 24), 58 | padding: EdgeInsets.all(16), 59 | backgroundGradient: GradientPlus.linear( 60 | colors: [ 61 | Colors.yellow, 62 | Colors.orange, 63 | Colors.pink, 64 | ], 65 | begin: Alignment.topLeft, 66 | end: Alignment.centerRight, 67 | ), 68 | backgroundRadius: RadiusPlus.all(10), 69 | backgroundBorder: BorderPlus( 70 | color: Colors.blue, 71 | width: 2, 72 | ), 73 | textShadows: [ 74 | ShadowPlus( 75 | color: Colors.black45, 76 | blur: 10, 77 | ) 78 | ], 79 | ); 80 | } 81 | 82 | Widget _buildExample3() { 83 | return TextPlus( 84 | '00000000000', 85 | margin: EdgeInsets.only(top: 24), 86 | padding: EdgeInsets.all(16), 87 | backgroundColor: Colors.black, 88 | color: Colors.white, 89 | fontSize: 20, 90 | mask: '###.###.###-##', 91 | onTap: () { 92 | print('Exemplo 3'); 93 | }, 94 | ); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 8 | 12 | 19 | 23 | 27 | 32 | 36 | 37 | 38 | 39 | 40 | 41 | 43 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /lib/src/utils/src/bottom_sheet_plus.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import '../../../flutter_plus.dart'; 4 | 5 | final bottomSheetPlus = BottomSheetPlus._instance; 6 | 7 | class BottomSheetPlus { 8 | static final _instance = BottomSheetPlus._(); 9 | BottomSheetPlus._(); 10 | 11 | /// Shows custom BottomSheet 12 | void show({ 13 | required Widget child, 14 | Function(dynamic result)? onClosed, 15 | Color? backgroundColor, 16 | Color? barrierColor, 17 | bool isDismissible = true, 18 | bool isScrollControlled = false, 19 | bool enableDrag = true, 20 | double elevation = 0, 21 | double? heightPercentScreen, 22 | double? height, 23 | Clip clipBehavior = Clip.none, 24 | RadiusPlus? radius, 25 | BorderPlus? border, 26 | }) { 27 | FocusManager.instance.primaryFocus!.unfocus(); 28 | 29 | var _validCustomHeight = (height != null && height > 0) || 30 | (heightPercentScreen != null && 31 | heightPercentScreen > 0 && 32 | heightPercentScreen <= 1); 33 | 34 | if (isScrollControlled == false && _validCustomHeight == true) { 35 | isScrollControlled = true; 36 | } 37 | showModalBottomSheet( 38 | context: navigatorPlus.currentContext!, 39 | backgroundColor: backgroundColor, 40 | barrierColor: barrierColor, 41 | isDismissible: isDismissible, 42 | isScrollControlled: isScrollControlled, 43 | enableDrag: enableDrag, 44 | elevation: elevation, 45 | clipBehavior: clipBehavior, 46 | shape: RoundedRectangleBorder( 47 | borderRadius: radius?.toBorderRadius ?? BorderRadius.zero, 48 | side: border?.toBorderSide ?? BorderSide.none, 49 | ), 50 | builder: (context) { 51 | if (height != null && height > 0) { 52 | child = SizedBox( 53 | height: height, 54 | child: child, 55 | ); 56 | } else if (heightPercentScreen != null) { 57 | if (heightPercentScreen > 0 && heightPercentScreen <= 1) { 58 | var _screenHeight = MediaQuery.of(context).size.height; 59 | var percentHeight = _screenHeight * heightPercentScreen; 60 | child = SizedBox( 61 | height: percentHeight, 62 | child: child, 63 | ); 64 | } else { 65 | print( 66 | '[flutter_plus] heightPercentScreen: min > 0.0 and max <= 1.0'); 67 | } 68 | } 69 | 70 | if (radius != null) { 71 | return ClipRRect( 72 | borderRadius: radius.toBorderRadius, 73 | child: child, 74 | ); 75 | } else { 76 | return child; 77 | } 78 | }, 79 | ).then((result) { 80 | if (onClosed != null) onClosed(result); 81 | }); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /lib/src/extensions/src/num_extension_plus.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | import 'package:intl/intl.dart'; 3 | 4 | extension NumExtensionPlus on num { 5 | /// Num to locale currency with symbol or not 6 | String? toCurrency({bool? withSymbol}) { 7 | if (isNullOrZero) { 8 | return null; 9 | } else { 10 | if (withSymbol == false) { 11 | return NumberFormat.simpleCurrency(name: '').format(this).trim(); 12 | } else { 13 | return NumberFormat.simpleCurrency().format(this).trim(); 14 | } 15 | } 16 | } 17 | 18 | /// Num to locale compact currency with symbol or not 19 | String? toCurrencyCompact({bool? withSymbol}) { 20 | if (isNullOrZero) { 21 | return null; 22 | } else { 23 | if (withSymbol == false) { 24 | return NumberFormat.compactSimpleCurrency(name: '').format(this).trim(); 25 | } else { 26 | return NumberFormat.compactSimpleCurrency().format(this).trim(); 27 | } 28 | } 29 | } 30 | 31 | /// Num with specific fraction digits 32 | double toPrecision(int fractionDigits) { 33 | if (isNullOrZero) { 34 | return -1.0; 35 | } else { 36 | var mod = pow(10, fractionDigits.toDouble()).toDouble(); 37 | return ((this * mod).round().toDouble() / mod); 38 | } 39 | } 40 | 41 | /// Transform number of days into hours 42 | num get daysToHours { 43 | if (isNullOrZero) { 44 | return -1; 45 | } else { 46 | return this * Duration.hoursPerDay; 47 | } 48 | } 49 | 50 | /// Transform number of minutes into hours 51 | num get minutesToHours { 52 | if (isNullOrZero) { 53 | return -1; 54 | } else { 55 | return this / Duration.minutesPerHour; 56 | } 57 | } 58 | 59 | /// Transform number of seconds into hours 60 | num get secondsToHours { 61 | // 3600 seconds = 1 hour 62 | if (isNullOrZero) { 63 | return -1; 64 | } else { 65 | return this / Duration.secondsPerHour; 66 | } 67 | } 68 | 69 | /// Transform number of hours into days 70 | num get hoursToDays { 71 | // 24 hours = 1 day 72 | if (isNullOrZero) { 73 | return -1; 74 | } else { 75 | return this * Duration.hoursPerDay; 76 | } 77 | } 78 | 79 | /// Transform number of seconds into minutes 80 | num get secondsToMinutes { 81 | // 60 seconds = 1 minute 82 | if (isNullOrZero) { 83 | return -1; 84 | } else { 85 | return this / Duration.secondsPerMinute; 86 | } 87 | } 88 | 89 | /// Transform number of hours into minutes 90 | num get hoursToMinutes { 91 | // 60 seconds = 1 minute 92 | if (isNullOrZero) { 93 | return -1; 94 | } else { 95 | return this * Duration.minutesPerHour; 96 | } 97 | } 98 | 99 | /// Checks whether number is 0 or null 100 | bool get isNullOrZero { 101 | if (this == 0) { 102 | return true; 103 | } else { 104 | return false; 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /example/lib/src/screens/text_field_plus_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_plus/flutter_plus.dart'; 3 | 4 | class TextFieldPlusScreen extends StatelessWidget { 5 | @override 6 | Widget build(BuildContext context) { 7 | return Scaffold( 8 | appBar: AppBar( 9 | title: TextPlus( 10 | 'TextFieldPlus Example', 11 | color: Colors.white, 12 | fontWeight: FontWeight.bold, 13 | ), 14 | backgroundColor: Colors.red, 15 | ), 16 | body: _buildBody(), 17 | ); 18 | } 19 | 20 | Widget _buildBody() { 21 | return SingleChildScrollView( 22 | padding: EdgeInsets.all(24), 23 | child: Center( 24 | child: Column( 25 | mainAxisAlignment: MainAxisAlignment.center, 26 | crossAxisAlignment: CrossAxisAlignment.center, 27 | children: [ 28 | _buildExample1(), 29 | _buildExample2(), 30 | _buildExample3(), 31 | ], 32 | ), 33 | ), 34 | ); 35 | } 36 | 37 | Widget _buildExample1() { 38 | return TextFieldPlus( 39 | padding: EdgeInsets.symmetric(horizontal: 8), 40 | height: 60, 41 | backgroundColor: Colors.black12, 42 | cursorColor: Colors.red, 43 | enabled: true, 44 | textInputType: TextInputType.emailAddress, 45 | placeholder: TextPlus( 46 | 'E-mail', 47 | color: Colors.black38, 48 | ), 49 | prefixWidget: Icon( 50 | Icons.alternate_email, 51 | color: Colors.redAccent, 52 | ), 53 | suffixWidget: Icon( 54 | Icons.email, 55 | color: Colors.redAccent, 56 | ), 57 | ); 58 | } 59 | 60 | Widget _buildExample2() { 61 | return TextFieldPlus( 62 | margin: EdgeInsets.only(top: 24), 63 | padding: EdgeInsets.symmetric(horizontal: 8), 64 | height: 60, 65 | backgroundColor: Colors.black12, 66 | cursorColor: Colors.red, 67 | textInputType: TextInputType.number, 68 | mask: '###.###.###-##', 69 | placeholder: TextPlus( 70 | 'CPF', 71 | color: Colors.black38, 72 | ), 73 | ); 74 | } 75 | 76 | Widget _buildExample3() { 77 | return TextFieldPlus( 78 | margin: EdgeInsets.only(top: 24), 79 | padding: EdgeInsets.symmetric(horizontal: 8), 80 | height: 60, 81 | cursorColor: Colors.white, 82 | textCapitalization: TextCapitalization.words, 83 | maxLines: 1, 84 | letterSpacing: 2, 85 | gradient: GradientPlus.linear( 86 | colors: [ 87 | Colors.red, 88 | Colors.orange, 89 | Colors.yellow, 90 | ], 91 | ), 92 | radius: RadiusPlus.all(12), 93 | placeholder: TextPlus( 94 | 'Name', 95 | color: Colors.white70, 96 | ), 97 | suffixWidget: Icon( 98 | Icons.person, 99 | color: Colors.white70, 100 | ), 101 | textColor: Colors.white, 102 | fontSize: 16, 103 | fontWeight: FontWeight.bold, 104 | ); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: example 2 | description: A new Flutter project. 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 | # The following defines the version and build number for your application. 9 | # A version number is three numbers separated by dots, like 1.2.43 10 | # followed by an optional build number separated by a +. 11 | # Both the version and the builder number may be overridden in flutter 12 | # build by specifying --build-name and --build-number, respectively. 13 | # In Android, build-name is used as versionName while build-number used as versionCode. 14 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 15 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. 16 | # Read more about iOS versioning at 17 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 18 | version: 1.0.0+1 19 | 20 | environment: 21 | sdk: ">=2.12.0 <3.0.0" 22 | 23 | dependencies: 24 | flutter: 25 | sdk: flutter 26 | 27 | # The following adds the Cupertino Icons font to your application. 28 | # Use with the CupertinoIcons class for iOS style icons. 29 | cupertino_icons: ^1.0.2 30 | 31 | flutter_plus: 32 | path: ../ 33 | url_launcher: ^6.0.3 34 | 35 | dev_dependencies: 36 | flutter_test: 37 | sdk: flutter 38 | 39 | # For information on the generic Dart part of this file, see the 40 | # following page: https://dart.dev/tools/pub/pubspec 41 | 42 | # The following section is specific to Flutter. 43 | flutter: 44 | 45 | # The following line ensures that the Material Icons font is 46 | # included with your application, so that you can use the icons in 47 | # the material Icons class. 48 | uses-material-design: true 49 | 50 | # To add assets to your application, add an assets section, like this: 51 | # assets: 52 | # - images/a_dot_burr.jpeg 53 | # - images/a_dot_ham.jpeg 54 | 55 | # An image asset can refer to one or more resolution-specific "variants", see 56 | # https://flutter.dev/assets-and-images/#resolution-aware. 57 | 58 | # For details regarding adding assets from package dependencies, see 59 | # https://flutter.dev/assets-and-images/#from-packages 60 | 61 | # To add custom fonts to your application, add a fonts section here, 62 | # in this "flutter" section. Each entry in this list should have a 63 | # "family" key with the font family name, and a "fonts" key with a 64 | # list giving the asset and other descriptors for the font. For 65 | # example: 66 | # fonts: 67 | # - family: Schyler 68 | # fonts: 69 | # - asset: fonts/Schyler-Regular.ttf 70 | # - asset: fonts/Schyler-Italic.ttf 71 | # style: italic 72 | # - family: Trajan Pro 73 | # fonts: 74 | # - asset: fonts/TrajanPro.ttf 75 | # - asset: fonts/TrajanPro_Bold.ttf 76 | # weight: 700 77 | # 78 | # For details regarding fonts from package dependencies, 79 | # see https://flutter.dev/custom-fonts/#from-packages 80 | -------------------------------------------------------------------------------- /lib/src/utils/src/snack_bar_plus.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import '../../../flutter_plus.dart'; 4 | 5 | final snackBarPlus = SnackBarPlus._instance; 6 | 7 | class SnackBarPlus { 8 | static final _instance = SnackBarPlus._(); 9 | SnackBarPlus._(); 10 | 11 | final rootScaffoldMessengerKey = GlobalKey(); 12 | 13 | /// Shows custom SnackBar 14 | void show({ 15 | required Widget child, 16 | Color? backgroundColor, 17 | Duration? duration, 18 | SnackBarAction? action, 19 | Animation? animation, 20 | SnackBarBehavior? behavior, 21 | Key? key, 22 | double? elevation, 23 | double? width, 24 | EdgeInsetsGeometry? margin, 25 | EdgeInsetsGeometry? padding, 26 | Function()? onVisibile, 27 | ShapeBorder? shape, 28 | }) { 29 | var _snackBar = SnackBar( 30 | content: child, 31 | backgroundColor: backgroundColor, 32 | duration: duration ?? Duration(seconds: 3), 33 | action: action, 34 | animation: animation, 35 | behavior: behavior, 36 | elevation: elevation, 37 | key: key, 38 | margin: margin, 39 | onVisible: onVisibile, 40 | padding: padding, 41 | shape: shape, 42 | width: width, 43 | ); 44 | hideCurrentSnackBar(); 45 | rootScaffoldMessengerKey.currentState!.showSnackBar(_snackBar); 46 | } 47 | 48 | /// Shows default SnackBar with some customizations 49 | void showText( 50 | String text, { 51 | Color? textColor, 52 | int textLines = 3, 53 | double fontSize = 16, 54 | FontWeight fontWeight = FontWeight.normal, 55 | TextAlign textAlign = TextAlign.center, 56 | Color? backgroundColor, 57 | Duration? duration, 58 | SnackBarAction? action, 59 | Animation? animation, 60 | SnackBarBehavior? behavior, 61 | Key? key, 62 | double? elevation, 63 | double? width, 64 | EdgeInsetsGeometry? margin, 65 | EdgeInsetsGeometry? padding, 66 | Function()? onVisibile, 67 | ShapeBorder? shape, 68 | }) { 69 | var _snackBar = SnackBar( 70 | content: TextPlus( 71 | text, 72 | color: textColor, 73 | maxLines: textLines, 74 | textOverflow: TextOverflow.ellipsis, 75 | fontSize: fontSize, 76 | fontWeight: fontWeight, 77 | textAlign: textAlign, 78 | ), 79 | backgroundColor: backgroundColor, 80 | duration: duration ?? Duration(seconds: 3), 81 | action: action, 82 | animation: animation, 83 | behavior: behavior, 84 | elevation: elevation, 85 | key: key, 86 | margin: margin, 87 | onVisible: onVisibile, 88 | padding: padding, 89 | shape: shape, 90 | width: width, 91 | ); 92 | hideCurrentSnackBar(); 93 | rootScaffoldMessengerKey.currentState!.showSnackBar(_snackBar); 94 | } 95 | 96 | void removeCurrentSnackBar({ 97 | SnackBarClosedReason reson = SnackBarClosedReason.remove, 98 | }) { 99 | rootScaffoldMessengerKey.currentState!.removeCurrentSnackBar( 100 | reason: reson, 101 | ); 102 | } 103 | 104 | void hideCurrentSnackBar({ 105 | SnackBarClosedReason reson = SnackBarClosedReason.hide, 106 | }) { 107 | rootScaffoldMessengerKey.currentState!.hideCurrentSnackBar( 108 | reason: reson, 109 | ); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # Include option is buggy: 2 | # https://github.com/flutter/flutter/issues/62591 3 | # In case the include issue gets fixed, lines below INCLUDE_FIX 4 | # can be removed 5 | 6 | # include: package:effective_dart/analysis_options.1.2.0.yaml 7 | analyzer: 8 | strong-mode: 9 | implicit-casts: false 10 | linter: 11 | rules: 12 | await_only_futures: true 13 | # This one is desirable, but that's a lot of work for now 14 | public_member_api_docs: false 15 | # Desirable, but would be breaking changes: 16 | avoid_positional_boolean_parameters: false 17 | constant_identifier_names: false 18 | include_file_not_found: false 19 | 20 | # INCLUDE_FIX (copy of effective dart 1.2.0) 21 | # STYLE 22 | camel_case_types: true 23 | camel_case_extensions: true 24 | library_names: true 25 | file_names: true 26 | library_prefixes: true 27 | non_constant_identifier_names: true 28 | directives_ordering: true 29 | lines_longer_than_80_chars: true # avoid 30 | curly_braces_in_flow_control_structures: true 31 | 32 | # DOCUMENTATION 33 | slash_for_doc_comments: true 34 | package_api_docs: true # prefer 35 | #- comment_references # Unused because https://github.com/dart-lang/sdk/issues/36974 36 | 37 | # USAGE 38 | implementation_imports: true 39 | avoid_relative_lib_imports: true # prefer 40 | prefer_relative_imports: true # prefer 41 | prefer_adjacent_string_concatenation: true 42 | prefer_interpolation_to_compose_strings: true # prefer 43 | unnecessary_brace_in_string_interps: true # avoid 44 | prefer_collection_literals: true 45 | avoid_function_literals_in_foreach_calls: true # avoid 46 | prefer_iterable_whereType: true 47 | prefer_function_declarations_over_variables: true 48 | unnecessary_lambdas: true 49 | prefer_equal_for_default_values: true 50 | avoid_init_to_null: true 51 | unnecessary_getters_setters: true 52 | annotate_overrides: true 53 | #- unnecessary_getters # prefer # Disabled pending fix: https://github.com/dart-lang/linter/issues/23 54 | #- prefer_expression_function_bodies # consider 55 | unnecessary_this: true 56 | prefer_initializing_formals: true 57 | type_init_formals: true 58 | empty_constructor_bodies: true 59 | unnecessary_new: true 60 | unnecessary_const: true 61 | avoid_catches_without_on_clauses: true # avoid 62 | avoid_catching_errors: true 63 | use_rethrow_when_possible: true 64 | 65 | # DESIGN 66 | use_to_and_as_if_applicable: true # prefer 67 | one_member_abstracts: true # avoid 68 | avoid_classes_with_only_static_members: true # avoid 69 | prefer_mixin: true 70 | prefer_final_fields: true # prefer 71 | use_setters_to_change_properties: true 72 | avoid_setters_without_getters: true 73 | avoid_returning_null: true # avoid 74 | avoid_returning_this: true # avoid 75 | type_annotate_public_apis: true # prefer 76 | #- prefer_typing_uninitialized_variables # consider 77 | omit_local_variable_types: true # avoid 78 | avoid_types_on_closure_parameters: true # avoid 79 | avoid_return_types_on_setters: true # avoid 80 | prefer_generic_function_type_aliases: true 81 | avoid_private_typedef_functions: true # prefer 82 | #- use_function_type_syntax_for_parameters # consider 83 | hash_and_equals: true 84 | avoid_equals_and_hash_code_on_mutable_classes: true # avoid 85 | avoid_null_checks_in_equality_operators: true 86 | -------------------------------------------------------------------------------- /lib/src/utils/src/navigator_plus.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | final navigatorPlus = NavigatorPlus._instance; 4 | 5 | class NavigatorPlus { 6 | static final _instance = NavigatorPlus._(); 7 | NavigatorPlus._(); 8 | 9 | GlobalKey? _navigatorKey = GlobalKey(); 10 | 11 | GlobalKey? get _getNavigatorKey { 12 | if (_navigatorKey == null || _navigatorKey!.currentState == null) { 13 | print('Need configuration'); 14 | return null; 15 | } else { 16 | return _navigatorKey; 17 | } 18 | } 19 | 20 | GlobalKey? get key { 21 | return _navigatorKey; 22 | } 23 | 24 | GlobalKey? addKey(GlobalKey? newKey) { 25 | _navigatorKey = newKey; 26 | return _navigatorKey; 27 | } 28 | 29 | BuildContext? get currentContext => 30 | _getNavigatorKey?.currentState?.overlay?.context; 31 | 32 | /// Navigate to a specific Widget 33 | Future? show( 34 | Widget destination, { 35 | bool? replace, 36 | bool? maintainState, 37 | RouteSettings? settings, 38 | }) { 39 | FocusManager.instance.primaryFocus!.unfocus(); 40 | if (replace != null && replace == true) { 41 | return _getNavigatorKey?.currentState?.pushReplacement( 42 | MaterialPageRoute( 43 | builder: (context) => destination, 44 | fullscreenDialog: false, 45 | maintainState: maintainState ?? true, 46 | settings: settings ?? null), 47 | ); 48 | } else { 49 | return _getNavigatorKey?.currentState?.push( 50 | MaterialPageRoute( 51 | builder: (context) => destination, 52 | fullscreenDialog: false, 53 | maintainState: maintainState ?? true, 54 | settings: settings ?? null), 55 | ); 56 | } 57 | } 58 | 59 | /// Navigate to a modal specific Widget 60 | Future? showModal( 61 | Widget destination, { 62 | bool? replace, 63 | bool? maintainState, 64 | RouteSettings? settings, 65 | }) { 66 | FocusManager.instance.primaryFocus!.unfocus(); 67 | if (replace != null && replace == true) { 68 | return _getNavigatorKey?.currentState?.pushReplacement( 69 | MaterialPageRoute( 70 | builder: (context) => destination, 71 | fullscreenDialog: true, 72 | maintainState: maintainState ?? true, 73 | settings: settings ?? null), 74 | ); 75 | } else { 76 | return _getNavigatorKey?.currentState?.push( 77 | MaterialPageRoute( 78 | builder: (context) => destination, 79 | fullscreenDialog: true, 80 | maintainState: maintainState ?? true, 81 | settings: settings ?? null), 82 | ); 83 | } 84 | } 85 | 86 | /// Check if you can return 87 | bool get canBack { 88 | if (_getNavigatorKey == null || _getNavigatorKey!.currentState == null) { 89 | return false; 90 | } else { 91 | return _getNavigatorKey!.currentState!.canPop(); 92 | } 93 | } 94 | 95 | /// Back to previous Widget 96 | void back({dynamic result}) { 97 | FocusManager.instance.primaryFocus!.unfocus(); 98 | if (canBack) _getNavigatorKey!.currentState!.pop(result); 99 | } 100 | 101 | /// Back to first stack widget 102 | void backAll() { 103 | FocusManager.instance.primaryFocus!.unfocus(); 104 | if (canBack) { 105 | _getNavigatorKey!.currentState!.popUntil((route) => route.isFirst); 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /example/lib/src/screens/container_plus_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_plus/flutter_plus.dart'; 3 | 4 | class ContainerPlusScreen extends StatefulWidget { 5 | @override 6 | _ContainerPlusScreenState createState() => _ContainerPlusScreenState(); 7 | } 8 | 9 | class _ContainerPlusScreenState extends State { 10 | @override 11 | Widget build(BuildContext context) { 12 | return Scaffold( 13 | appBar: AppBar( 14 | title: TextPlus( 15 | 'ContainerPlus Example', 16 | color: Colors.white, 17 | fontWeight: FontWeight.bold, 18 | ), 19 | backgroundColor: Colors.red, 20 | ), 21 | body: _buildBody(), 22 | ); 23 | } 24 | 25 | Widget _buildBody() { 26 | return SingleChildScrollView( 27 | padding: EdgeInsets.all(24), 28 | child: Center( 29 | child: Column( 30 | mainAxisAlignment: MainAxisAlignment.center, 31 | crossAxisAlignment: CrossAxisAlignment.center, 32 | children: [ 33 | _buildExample1(), 34 | _buildExample2(), 35 | _buildExample3(), 36 | ], 37 | ), 38 | ), 39 | ); 40 | } 41 | 42 | Widget _buildExample1() { 43 | return ContainerPlus( 44 | width: 150, 45 | height: 150, 46 | radius: RadiusPlus.all(20), 47 | color: Colors.yellow, 48 | shadows: [ 49 | ShadowPlus( 50 | color: Colors.red, 51 | moveDown: -10, 52 | moveRight: -10, 53 | blur: 5, 54 | spread: 1, 55 | opacity: 0.2, 56 | ), 57 | ShadowPlus( 58 | color: Colors.blue, 59 | moveDown: 10, 60 | moveRight: 10, 61 | blur: 10, 62 | spread: 5, 63 | opacity: 0.5, 64 | ), 65 | ], 66 | border: BorderPlus( 67 | color: Colors.black, 68 | width: 2, 69 | ), 70 | child: TextPlus( 71 | 'EXAMPLE 1', 72 | isCenter: true, 73 | color: Colors.white, 74 | ), 75 | ); 76 | } 77 | 78 | Widget _buildExample2() { 79 | return ContainerPlus( 80 | margin: EdgeInsets.only(top: 48), 81 | width: 150, 82 | height: 150, 83 | isCircle: true, 84 | gradient: GradientPlus.linear( 85 | colors: [ 86 | Colors.yellow, 87 | Colors.orange, 88 | Colors.pink, 89 | ], 90 | begin: Alignment.topLeft, 91 | end: Alignment.centerRight, 92 | ), 93 | innerShadows: [ 94 | InnerShadowPlus( 95 | color: Colors.green, 96 | blur: 10, 97 | ) 98 | ], 99 | child: TextPlus( 100 | 'EXAMPLE 2', 101 | isCenter: true, 102 | color: Colors.white, 103 | ), 104 | ); 105 | } 106 | 107 | bool skeletonEnabled = false; 108 | 109 | Widget _buildExample3() { 110 | return ContainerPlus( 111 | margin: EdgeInsets.only(top: 48), 112 | width: 150, 113 | height: 150, 114 | color: Colors.black, 115 | radius: RadiusPlus.only(topLeft: 40, bottomRight: 10), 116 | skeleton: SkeletonPlus.automatic(enabled: skeletonEnabled), 117 | onTap: () { 118 | setState(() { 119 | skeletonEnabled = !skeletonEnabled; 120 | }); 121 | Future.delayed(Duration(seconds: 5), () { 122 | setState(() { 123 | skeletonEnabled = !skeletonEnabled; 124 | }); 125 | }); 126 | }, 127 | child: TextPlus( 128 | 'EXAMPLE 3', 129 | isCenter: true, 130 | color: Colors.white, 131 | ), 132 | ); 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /example/lib/src/screens/compare_widget_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_plus/flutter_plus.dart'; 3 | 4 | class CompareWidgetScreen extends StatelessWidget { 5 | @override 6 | Widget build(BuildContext context) { 7 | return Scaffold( 8 | appBar: AppBar( 9 | title: TextPlus( 10 | 'Compare Widgets', 11 | color: Colors.white, 12 | fontWeight: FontWeight.bold, 13 | ), 14 | backgroundColor: Colors.red, 15 | ), 16 | backgroundColor: utilsPlus.colorHex('161718'), 17 | body: _buildBody(), 18 | ); 19 | } 20 | 21 | Widget _buildBody() { 22 | return SingleChildScrollView( 23 | padding: EdgeInsets.all(24), 24 | child: Center( 25 | child: Column( 26 | mainAxisAlignment: MainAxisAlignment.center, 27 | crossAxisAlignment: CrossAxisAlignment.center, 28 | children: [ 29 | _buildContainerPlus(), 30 | SizedBox( 31 | height: 48, 32 | ), 33 | _buildNativeContainer(), 34 | ], 35 | ), 36 | ), 37 | ); 38 | } 39 | 40 | Widget _buildNativeContainer() { 41 | return GestureDetector( 42 | child: Container( 43 | height: 200, 44 | width: 200, 45 | decoration: BoxDecoration( 46 | border: Border.all( 47 | color: Colors.white, 48 | width: 2, 49 | ), 50 | gradient: LinearGradient( 51 | colors: [ 52 | Colors.pink, 53 | Colors.blue, 54 | ], 55 | begin: Alignment.topLeft, 56 | end: Alignment.bottomRight, 57 | ), 58 | borderRadius: BorderRadius.all( 59 | Radius.circular(30), 60 | ), 61 | boxShadow: [ 62 | BoxShadow( 63 | color: Colors.yellow.withOpacity( 64 | 0.6, 65 | ), 66 | blurRadius: 6, 67 | offset: Offset( 68 | -5, 69 | -5, 70 | ), 71 | ), 72 | BoxShadow( 73 | color: Colors.green.withOpacity( 74 | 0.6, 75 | ), 76 | blurRadius: 6, 77 | offset: Offset( 78 | 5, 79 | 5, 80 | ), 81 | ), 82 | ], 83 | ), 84 | child: Center( 85 | child: Text( 86 | 'Container', 87 | style: TextStyle( 88 | color: Colors.white, 89 | fontSize: 18, 90 | fontWeight: FontWeight.bold, 91 | ), 92 | ), 93 | ), 94 | ), 95 | onTap: () { 96 | print('NativeContainer'); 97 | }, 98 | ); 99 | } 100 | 101 | Widget _buildContainerPlus() { 102 | return ContainerPlus( 103 | height: 200, 104 | width: 200, 105 | radius: RadiusPlus.all(30), 106 | gradient: GradientPlus.linear( 107 | colors: [ 108 | Colors.pink, 109 | Colors.blue, 110 | ], 111 | begin: Alignment.topLeft, 112 | end: Alignment.bottomRight, 113 | ), 114 | shadows: [ 115 | ShadowPlus( 116 | color: Colors.yellow, 117 | opacity: 0.6, 118 | blur: 6, 119 | moveDown: -5, 120 | moveRight: -5, 121 | ), 122 | ShadowPlus( 123 | color: Colors.green, 124 | opacity: 0.6, 125 | blur: 6, 126 | moveDown: 5, 127 | moveRight: 5, 128 | ), 129 | ], 130 | border: BorderPlus( 131 | color: Colors.white, 132 | width: 2, 133 | ), 134 | child: TextPlus( 135 | 'ContainerPlus', 136 | isCenter: true, 137 | color: Colors.white, 138 | fontSize: 18, 139 | fontWeight: FontWeight.bold, 140 | ), 141 | onTap: () { 142 | print('FlutterPlus'); 143 | }, 144 | ); 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /example/lib/src/screens/button_plus_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_plus/flutter_plus.dart'; 3 | 4 | class ButtonPlusScreen extends StatefulWidget { 5 | @override 6 | _ButtonPlusScreenState createState() => _ButtonPlusScreenState(); 7 | } 8 | 9 | class _ButtonPlusScreenState extends State { 10 | @override 11 | Widget build(BuildContext context) { 12 | return Scaffold( 13 | appBar: AppBar( 14 | title: TextPlus( 15 | 'ButtonPlus Example', 16 | color: Colors.white, 17 | fontWeight: FontWeight.bold, 18 | ), 19 | backgroundColor: Colors.red, 20 | ), 21 | body: _buildBody(), 22 | ); 23 | } 24 | 25 | Widget _buildBody() { 26 | return SingleChildScrollView( 27 | padding: EdgeInsets.all(24), 28 | child: Center( 29 | child: Column( 30 | mainAxisAlignment: MainAxisAlignment.center, 31 | crossAxisAlignment: CrossAxisAlignment.center, 32 | children: [ 33 | _buildExample1(), 34 | _buildExample2(), 35 | _buildExample3(), 36 | _buildExample4(), 37 | ], 38 | ), 39 | ), 40 | ); 41 | } 42 | 43 | Widget _buildExample1() { 44 | return ButtonPlus( 45 | width: 200, 46 | height: 60, 47 | radius: RadiusPlus.all(12), 48 | color: Colors.blue, 49 | enabled: true, 50 | splashColor: Colors.red, 51 | highlightColor: Colors.yellow, 52 | focusColor: Colors.green, 53 | hoverColor: Colors.pink, 54 | child: TextPlus( 55 | 'EXAMPLE 1', 56 | color: Colors.white, 57 | ), 58 | onPressed: () { 59 | print('EXAMPLE 1'); 60 | }, 61 | ); 62 | } 63 | 64 | Widget _buildExample2() { 65 | return ButtonPlus( 66 | margin: EdgeInsets.only(top: 48), 67 | width: 200, 68 | height: 60, 69 | radius: RadiusPlus.bottom(20), 70 | color: Colors.yellow, 71 | splashColor: Colors.red, 72 | shadows: [ 73 | ShadowPlus( 74 | color: Colors.red, 75 | moveDown: -10, 76 | moveRight: -10, 77 | blur: 5, 78 | spread: 1, 79 | opacity: 0.2, 80 | ), 81 | ShadowPlus( 82 | color: Colors.blue, 83 | moveDown: 10, 84 | moveRight: 10, 85 | blur: 10, 86 | spread: 5, 87 | opacity: 0.5, 88 | ), 89 | ], 90 | border: BorderPlus( 91 | color: Colors.black, 92 | width: 2, 93 | ), 94 | child: TextPlus( 95 | 'EXAMPLE 2', 96 | color: Colors.white, 97 | ), 98 | onPressed: () { 99 | print('EXAMPLE 2'); 100 | }, 101 | ); 102 | } 103 | 104 | Widget _buildExample3() { 105 | return ButtonPlus( 106 | margin: EdgeInsets.only(top: 48), 107 | width: 200, 108 | height: 60, 109 | isCircle: true, 110 | gradient: GradientPlus.linear( 111 | colors: [ 112 | Colors.yellow, 113 | Colors.orange, 114 | Colors.pink, 115 | ], 116 | begin: Alignment.topLeft, 117 | end: Alignment.centerRight, 118 | ), 119 | innerShadows: [ 120 | InnerShadowPlus( 121 | color: Colors.green, 122 | blur: 10, 123 | ) 124 | ], 125 | child: TextPlus( 126 | 'EXAMPLE 3', 127 | color: Colors.white, 128 | ), 129 | onPressed: () { 130 | print('EXAMPLE 3'); 131 | }, 132 | ); 133 | } 134 | 135 | bool isLoading = false; 136 | 137 | Widget _buildExample4() { 138 | return ButtonPlus( 139 | margin: EdgeInsets.only(top: 48), 140 | width: 200, 141 | height: 60, 142 | color: Colors.black, 143 | radius: RadiusPlus.only(topLeft: 40, bottomRight: 10), 144 | skeleton: SkeletonPlus.automatic(enabled: isLoading), 145 | child: TextPlus( 146 | 'EXAMPLE 4', 147 | color: Colors.white, 148 | ), 149 | onPressed: () { 150 | print('EXAMPLE 4'); 151 | 152 | setState(() { 153 | isLoading = !isLoading; 154 | }); 155 | Future.delayed(Duration(seconds: 5), () { 156 | setState(() { 157 | isLoading = !isLoading; 158 | }); 159 | }); 160 | }, 161 | ); 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /lib/src/widgets/src/button_plus.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import '../../../flutter_plus.dart'; 4 | 5 | class ButtonPlus extends StatefulWidget { 6 | /* 7 | Todo 8 | 1- isLoading - show progress 9 | 2- tap feedback 10 | */ 11 | 12 | /// ButtonPlus child 13 | final Widget? child; 14 | 15 | /// ButtonPlus padding 16 | final EdgeInsets padding; 17 | 18 | /// ButtonPlus margin 19 | final EdgeInsets? margin; 20 | 21 | /// ButtonPlus height 22 | final double? height; 23 | 24 | /// ButtonPlus width 25 | final double? width; 26 | 27 | /// ButtonPlus alignment 28 | final Alignment? alignment; 29 | 30 | /// ButtonPlus decoration image 31 | final DecorationImage? image; 32 | 33 | /// ButtonPlus color when there is no gradient 34 | final Color? color; 35 | 36 | /// ButtonPlus disabledBackgroundColor 37 | final Color? disabledBackgroundColor; 38 | 39 | /// ButtonPlus onPressed action 40 | final Function()? onPressed; 41 | 42 | /// ButtonPlus onLongPress action 43 | final Function()? onLongPress; 44 | 45 | /// ButtonPlus splashColor 46 | final Color? splashColor; 47 | 48 | /// ButtonPlus highlightColor 49 | final Color? highlightColor; 50 | 51 | /// ButtonPlus focusColor 52 | final Color? focusColor; 53 | 54 | /// ButtonPlus hoverColor 55 | final Color? hoverColor; 56 | 57 | /// ButtonPlus radius 58 | final RadiusPlus? radius; 59 | 60 | /// ButtonPlus border 61 | final BorderPlus? border; 62 | 63 | /// ButtonPlus shadows 64 | final List? shadows; 65 | 66 | /// ButtonPlus gradient 67 | final GradientPlus? gradient; 68 | 69 | /// ButtonPlus innerShadows 70 | final List? innerShadows; 71 | 72 | /// ButtonPlus skeleton 73 | final SkeletonPlus? skeleton; 74 | 75 | /// ButtonPlus enabled -> true or false 76 | final bool? enabled; 77 | 78 | /// ButtonPlus inside Center widget 79 | final bool isCenter; 80 | 81 | /// ButtonPlus inside Expanded widget 82 | final bool isExpanded; 83 | 84 | /// ButtonPlus circle radius 85 | final bool isCircle; 86 | 87 | ButtonPlus({ 88 | Key? key, 89 | this.child, 90 | this.padding = EdgeInsets.zero, 91 | this.margin, 92 | this.height, 93 | this.width, 94 | this.color, 95 | this.disabledBackgroundColor, 96 | this.alignment, 97 | //bools 98 | this.isCenter = false, 99 | this.isExpanded = false, 100 | this.isCircle = false, 101 | this.enabled, 102 | // actions 103 | this.onPressed, 104 | this.onLongPress, 105 | this.splashColor, 106 | this.highlightColor, 107 | this.focusColor, 108 | this.hoverColor, 109 | // Plus 110 | this.radius, 111 | this.border, 112 | this.shadows, 113 | this.gradient, 114 | this.image, 115 | this.skeleton, 116 | this.innerShadows, 117 | }); 118 | 119 | @override 120 | _ButtomPlusState createState() => _ButtomPlusState(); 121 | } 122 | 123 | class _ButtomPlusState extends State { 124 | @override 125 | Widget build(BuildContext context) { 126 | return _buildButtomPlus(); 127 | } 128 | 129 | Widget _buildButtomPlus() { 130 | return ContainerPlus( 131 | padding: EdgeInsets.zero, 132 | margin: widget.margin, 133 | isCenter: widget.isCenter, 134 | isExpanded: widget.isExpanded, 135 | isCircle: widget.isCircle, 136 | alignment: widget.alignment, 137 | color: widget.color, 138 | height: widget.height, 139 | width: widget.width, 140 | border: widget.border, 141 | gradient: widget.gradient, 142 | radius: widget.radius, 143 | shadows: widget.shadows, 144 | innerShadows: widget.innerShadows, 145 | skeleton: widget.skeleton, 146 | child: _buildChildButton(), 147 | ); 148 | } 149 | 150 | Widget _buildChildButton() { 151 | return TextButton( 152 | onPressed: isEnabled ? widget.onPressed : null, 153 | onLongPress: isEnabled ? widget.onLongPress : null, 154 | child: Padding( 155 | padding: widget.padding, 156 | child: widget.child, 157 | ), 158 | style: ButtonStyle( 159 | overlayColor: MaterialStateProperty.resolveWith( 160 | (states) { 161 | if (states.contains(MaterialState.focused)) { 162 | return widget.focusColor ?? Colors.transparent; 163 | } else if (states.contains(MaterialState.hovered)) { 164 | return widget.hoverColor ?? Colors.transparent; 165 | } else if (states.contains(MaterialState.pressed)) { 166 | return widget.splashColor ?? Colors.transparent; 167 | } else { 168 | return null; 169 | } 170 | }, 171 | ), 172 | ), 173 | ); 174 | } 175 | 176 | bool get isEnabled { 177 | if ((widget.onPressed == null && widget.onLongPress == null) || 178 | widget.enabled == false) { 179 | return false; 180 | } else { 181 | return true; 182 | } 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /lib/src/widgets/src/text_plus.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import '../../../flutter_plus.dart'; 4 | 5 | class TextPlus extends StatelessWidget { 6 | /* 7 | Todo 8 | urls 9 | phones 10 | dates 11 | onTap 12 | */ 13 | 14 | /// TextPlus text 15 | final String? text; 16 | 17 | /// TextPlus maxLines 18 | final int? maxLines; 19 | 20 | /// TextPlus mask -> ###.###.###-## 21 | final String? mask; 22 | 23 | /// TextPlus inside Center widget 24 | final bool isCenter; 25 | 26 | /// TextPlus inside Expanded widget 27 | final bool isExpanded; 28 | 29 | /// TextPlus height 30 | final double? height; 31 | 32 | /// TextPlus width 33 | final double? width; 34 | 35 | /// TextPlus padding 36 | final EdgeInsets padding; 37 | 38 | /// TextPlus margin 39 | final EdgeInsets margin; 40 | 41 | /// TextPlus textOverflow 42 | final TextOverflow? textOverflow; 43 | 44 | /// TextPlus textAlign 45 | final TextAlign textAlign; 46 | 47 | /// TextPlus textDirection 48 | final TextDirection textDirection; 49 | 50 | /// TextPlus color 51 | final Color? color; 52 | 53 | /// TextPlus fontSize 54 | final double? fontSize; 55 | 56 | /// TextPlus fontWeight 57 | final FontWeight fontWeight; 58 | 59 | /// TextPlus fontStyle 60 | final FontStyle fontStyle; 61 | 62 | /// TextPlus backgroundColor 63 | final Color? backgroundColor; 64 | 65 | /// TextPlus letterSpacing 66 | final double? letterSpacing; 67 | 68 | /// TextPlus wordSpacing 69 | final double? wordSpacing; 70 | 71 | /// TextPlus fontFamily 72 | final String? fontFamily; 73 | 74 | /// TextPlus textDecorationPlus 75 | final TextDecorationPlus? textDecorationPlus; 76 | 77 | /// TextPlus textShadows 78 | final List? textShadows; 79 | 80 | /// TextPlus radius 81 | final RadiusPlus? backgroundRadius; 82 | 83 | /// TextPlus border 84 | final BorderPlus? backgroundBorder; 85 | 86 | /// TextPlus shadows 87 | final List? backgroundShadows; 88 | 89 | /// TextPlus gradient 90 | final GradientPlus? backgroundGradient; 91 | 92 | /// TextPlus innerShadows 93 | final List? backgroundInnerShadows; 94 | 95 | /// TextPlus onTap action 96 | final Function()? onTap; 97 | 98 | /// TextPlus onLongPress action 99 | final Function()? onLongPress; 100 | 101 | TextPlus( 102 | this.text, { 103 | Key? key, 104 | this.maxLines, 105 | this.textOverflow, 106 | this.textAlign = TextAlign.left, 107 | this.textDirection = TextDirection.ltr, 108 | // style 109 | this.color = Colors.black, 110 | this.fontSize, 111 | this.fontWeight = FontWeight.normal, 112 | this.fontStyle = FontStyle.normal, 113 | this.backgroundColor, 114 | this.letterSpacing, 115 | this.wordSpacing, 116 | this.height, 117 | this.fontFamily, 118 | // custom 119 | this.mask, 120 | this.isCenter = false, 121 | this.isExpanded = false, 122 | this.textDecorationPlus, 123 | this.textShadows, 124 | this.padding = EdgeInsets.zero, 125 | this.margin = EdgeInsets.zero, 126 | this.onTap, 127 | this.onLongPress, 128 | this.width, 129 | this.backgroundBorder, 130 | this.backgroundShadows, 131 | this.backgroundInnerShadows, 132 | this.backgroundGradient, 133 | this.backgroundRadius, 134 | }) : super(key: key); 135 | 136 | @override 137 | Widget build(BuildContext context) { 138 | var _textPlus = _buildTextPlus(); 139 | 140 | if (isCenter == true) { 141 | _textPlus = Center( 142 | child: _textPlus, 143 | ); 144 | } 145 | 146 | if (isExpanded == true) { 147 | _textPlus = Expanded( 148 | child: _textPlus, 149 | ); 150 | } 151 | 152 | return _textPlus; 153 | } 154 | 155 | Widget _buildTextPlus() { 156 | return ContainerPlus( 157 | width: width, 158 | height: height, 159 | padding: padding, 160 | margin: margin, 161 | color: backgroundColor, 162 | onTap: onTap, 163 | onLongPress: onLongPress, 164 | border: backgroundBorder, 165 | shadows: backgroundShadows, 166 | innerShadows: backgroundInnerShadows, 167 | gradient: backgroundGradient, 168 | radius: backgroundRadius, 169 | child: Text( 170 | _maskText!, 171 | key: key, 172 | maxLines: maxLines, 173 | overflow: textOverflow, 174 | textAlign: textAlign, 175 | textDirection: textDirection, 176 | style: textStyle, 177 | ), 178 | ); 179 | } 180 | 181 | TextStyle get textStyle { 182 | return TextStyle( 183 | color: color, 184 | fontSize: fontSize, 185 | fontWeight: fontWeight, 186 | fontStyle: fontStyle, 187 | backgroundColor: Colors.transparent, 188 | decoration: textDecorationPlus?.textDecoration, 189 | decorationColor: textDecorationPlus?.color, 190 | decorationStyle: textDecorationPlus?.decorationStyle, 191 | decorationThickness: textDecorationPlus?.decorationThickness, 192 | letterSpacing: letterSpacing, 193 | fontFamily: fontFamily, 194 | wordSpacing: wordSpacing, 195 | // height: height, 196 | shadows: _buildShadows(), 197 | ); 198 | } 199 | 200 | String? get _maskText { 201 | try { 202 | if (text == null || text!.isEmpty) { 203 | return ''; 204 | } else if (mask == null || mask!.isEmpty) { 205 | return text; 206 | } else { 207 | var maskItemCount = 0; 208 | var maskedString = ''; 209 | for (var i = 0; i < mask!.length; i++) { 210 | if (mask![i] == '#') { 211 | maskedString += _cleanText[i - maskItemCount]; 212 | } else { 213 | maskedString += mask![i]; 214 | maskItemCount++; 215 | } 216 | } 217 | return maskedString; 218 | } 219 | } on Exception catch (e) { 220 | print(e); 221 | return '* invalid mask *'; 222 | } 223 | } 224 | 225 | String get _cleanText { 226 | return text!.replaceAll(RegExp(r'[^\w\s]+'), '').replaceAll(' ', ''); 227 | } 228 | 229 | List? _buildShadows() { 230 | if (textShadows == null || textShadows!.isEmpty) { 231 | return null; 232 | } else { 233 | return textShadows!.map((shadowPlus) { 234 | return Shadow( 235 | color: shadowPlus.opacity != null 236 | ? shadowPlus.color.withOpacity(shadowPlus.opacity!) 237 | : shadowPlus.color, 238 | blurRadius: shadowPlus.blur, 239 | offset: Offset( 240 | shadowPlus.moveRight, 241 | shadowPlus.moveDown, 242 | ), 243 | ); 244 | }).toList(); 245 | } 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /lib/src/components/src/text_field_mask_plus.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:flutter/cupertino.dart'; 4 | import 'package:flutter/services.dart'; 5 | 6 | class TextFieldMaskPlus extends TextInputFormatter { 7 | late String _mask; 8 | late List _maskChars; 9 | late Map _maskFilter; 10 | 11 | int? _maskLength; 12 | final _resultTextArray = []; 13 | String _resultTextMasked = ""; 14 | 15 | TextFieldMaskPlus({ 16 | String mask = "+# (###) ###-##-##", 17 | Map? filter, 18 | }) : assert(mask.isNotEmpty) { 19 | updateMask( 20 | mask, 21 | filter: filter ?? 22 | { 23 | "#": RegExp(r'[0-9]'), 24 | "A": RegExp(r'[^0-9]'), 25 | }, 26 | ); 27 | } 28 | 29 | /// Change the mask 30 | TextEditingValue updateMask(String mask, {Map? filter}) { 31 | _mask = mask; 32 | if (filter != null) { 33 | _updateFilter(filter); 34 | } 35 | _calcMaskLength(); 36 | final unmaskedText = getUnmaskedText(); 37 | _resultTextArray.clear(); 38 | _resultTextMasked = ""; 39 | return _formatUpdate( 40 | TextEditingValue(), 41 | TextEditingValue( 42 | text: unmaskedText, 43 | selection: TextSelection( 44 | baseOffset: unmaskedText.length, 45 | extentOffset: unmaskedText.length, 46 | ), 47 | ), 48 | ); 49 | } 50 | 51 | /// Get masked text, e.g. "+0 (123) 456-78-90" 52 | String getMaskedText() { 53 | return _resultTextMasked; 54 | } 55 | 56 | /// Get unmasked text, e.g. "01234567890" 57 | String getUnmaskedText() { 58 | return _resultTextArray.join(); 59 | } 60 | 61 | /// Check if target mask is filled 62 | bool isFill() { 63 | return _resultTextArray.length == _maskLength; 64 | } 65 | 66 | TextEditingValue? _lastResValue; 67 | TextEditingValue? _lastNewValue; 68 | 69 | @override 70 | TextEditingValue formatEditUpdate( 71 | TextEditingValue oldValue, TextEditingValue newValue) { 72 | if (_lastResValue == oldValue && newValue == _lastNewValue) { 73 | return _lastResValue!; 74 | } 75 | _lastNewValue = newValue; 76 | _lastResValue = _formatUpdate(oldValue, newValue); 77 | return _lastResValue!; 78 | } 79 | 80 | TextEditingValue _formatUpdate( 81 | TextEditingValue oldValue, TextEditingValue newValue) { 82 | final selectionBefore = oldValue.selection; 83 | 84 | final textBefore = oldValue.text; 85 | final textAfter = newValue.text; 86 | 87 | final startBefore = selectionBefore.start == -1 ? 0 : selectionBefore.start; 88 | final countBefore = selectionBefore.start == -1 || selectionBefore.end == -1 89 | ? 0 90 | : selectionBefore.end - selectionBefore.start; 91 | 92 | final after = textAfter.length - (textBefore.length - countBefore); 93 | final removed = after < 0 ? after.abs() : 0; 94 | 95 | final startAfter = max(0, startBefore + (after < 0 ? after : 0)); 96 | final endAfter = max(0, startAfter + (after > 0 ? after : 0)); 97 | 98 | final replaceStart = max(0, startBefore - removed); 99 | final replaceLength = countBefore + removed; 100 | 101 | final beforeResultTextLength = _resultTextArray.length; 102 | 103 | var currentTotalText = _resultTextArray.length; 104 | var selectionStart = 0; 105 | var selectionLength = 0; 106 | for (var i = 0; i < replaceStart + replaceLength; i++) { 107 | if (_maskChars.contains(_mask[i]) && currentTotalText > 0) { 108 | currentTotalText -= 1; 109 | if (i < replaceStart) { 110 | selectionStart += 1; 111 | } 112 | if (i >= replaceStart) { 113 | selectionLength += 1; 114 | } 115 | } 116 | } 117 | 118 | final replacementText = textAfter.substring(startAfter, endAfter); 119 | var targetCursorPosition = selectionStart; 120 | if (replacementText.isEmpty) { 121 | _resultTextArray.removeRange( 122 | selectionStart, selectionStart + selectionLength); 123 | } else { 124 | if (selectionLength > 0) { 125 | _resultTextArray.removeRange( 126 | selectionStart, selectionStart + selectionLength); 127 | } 128 | _insertToResultText(selectionStart, replacementText); 129 | targetCursorPosition += replacementText.length; 130 | } 131 | 132 | if (beforeResultTextLength == 0 && _resultTextArray.length > 1) { 133 | for (var i = 0; i < _mask.length; i++) { 134 | if (_maskChars.contains(_mask[i]) || _resultTextArray.length == 0) { 135 | break; 136 | } else if (_mask[i] == _resultTextArray[0]) { 137 | _resultTextArray.removeAt(0); 138 | } 139 | } 140 | } 141 | 142 | var curTextPos = 0; 143 | var maskPos = 0; 144 | _resultTextMasked = ""; 145 | var cursorPos = -1; 146 | var nonMaskedCount = 0; 147 | 148 | while (maskPos < _mask.length) { 149 | final curMaskChar = _mask[maskPos]; 150 | final isMaskChar = _maskChars.contains(curMaskChar); 151 | 152 | var curTextInRange = curTextPos < _resultTextArray.length; 153 | 154 | String? curTextChar; 155 | if (isMaskChar && curTextInRange) { 156 | while (curTextChar == null && curTextInRange) { 157 | final potentialTextChar = _resultTextArray[curTextPos]; 158 | if (_maskFilter[curMaskChar]!.hasMatch(potentialTextChar)) { 159 | curTextChar = potentialTextChar; 160 | } else { 161 | _resultTextArray.removeAt(curTextPos); 162 | curTextInRange = curTextPos < _resultTextArray.length; 163 | if (curTextPos <= targetCursorPosition) { 164 | targetCursorPosition -= 1; 165 | } 166 | } 167 | } 168 | } 169 | 170 | if (isMaskChar && curTextInRange) { 171 | _resultTextMasked += curTextChar!; 172 | if (curTextPos == targetCursorPosition && cursorPos == -1) { 173 | cursorPos = maskPos - nonMaskedCount; 174 | } 175 | nonMaskedCount = 0; 176 | curTextPos += 1; 177 | } else { 178 | if (curTextPos == targetCursorPosition && 179 | cursorPos == -1 && 180 | !curTextInRange) { 181 | cursorPos = maskPos; 182 | } 183 | 184 | if (!curTextInRange) { 185 | break; 186 | } else { 187 | _resultTextMasked += _mask[maskPos]; 188 | } 189 | 190 | nonMaskedCount++; 191 | } 192 | 193 | maskPos += 1; 194 | } 195 | 196 | if (nonMaskedCount > 0) { 197 | _resultTextMasked = _resultTextMasked.substring( 198 | 0, _resultTextMasked.length - nonMaskedCount); 199 | cursorPos -= nonMaskedCount; 200 | } 201 | 202 | if (_resultTextArray.length > _maskLength!) { 203 | _resultTextArray.removeRange(_maskLength!, _resultTextArray.length); 204 | } 205 | 206 | var finalCursorPosition = 207 | cursorPos == -1 ? _resultTextMasked.length : cursorPos; 208 | 209 | return TextEditingValue( 210 | text: _resultTextMasked, 211 | selection: TextSelection( 212 | baseOffset: finalCursorPosition, 213 | extentOffset: finalCursorPosition, 214 | affinity: newValue.selection.affinity, 215 | isDirectional: newValue.selection.isDirectional)); 216 | } 217 | 218 | void _insertToResultText(int start, String substring) { 219 | for (var i = 0; i < substring.length; i++) { 220 | _resultTextArray.insert(start + i, substring[i]); 221 | } 222 | } 223 | 224 | void _calcMaskLength() { 225 | _maskLength = 0; 226 | for (var i = 0; i < _mask.length; i++) { 227 | if (_maskChars.contains(_mask[i])) { 228 | var maskLength = _maskLength!; 229 | _maskLength = maskLength + 1; 230 | } 231 | } 232 | } 233 | 234 | void _updateFilter(Map filter) { 235 | _maskFilter = filter; 236 | _maskChars = _maskFilter.keys.toList(growable: false); 237 | } 238 | } 239 | -------------------------------------------------------------------------------- /lib/src/utils/src/dialog_plus.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import '../../../flutter_plus.dart'; 3 | 4 | final dialogPlus = DialogPlus._instance; 5 | 6 | class DialogPlus { 7 | static final _instance = DialogPlus._(); 8 | DialogPlus._(); 9 | 10 | /// Shows custom Dialog 11 | void show({ 12 | required Widget child, 13 | Color? barrierColor, 14 | bool barrierDismissible = true, 15 | bool useRootNavigator = false, 16 | bool useSafeArea = false, 17 | RouteSettings? routeSettings, 18 | bool closeKeyboardWhenOpen = true, 19 | RadiusPlus? radius, 20 | BorderPlus? border, 21 | double elevation = 1, 22 | double? screenHorizontalMargin, 23 | }) { 24 | if (closeKeyboardWhenOpen == true) { 25 | utilsPlus.closeKeyboard(); 26 | } 27 | showDialog( 28 | context: navigatorPlus.currentContext!, 29 | barrierColor: barrierColor, 30 | barrierDismissible: barrierDismissible, 31 | routeSettings: routeSettings, 32 | useRootNavigator: useRootNavigator, 33 | useSafeArea: useSafeArea, 34 | builder: (context) { 35 | return _createDialog( 36 | child, 37 | // SingleChildScrollView( 38 | // child: Column( 39 | // mainAxisSize: MainAxisSize.min, 40 | // children: [child], 41 | // ), 42 | // ), 43 | elevation, 44 | radius, 45 | border, 46 | screenHorizontalMargin, 47 | ); 48 | }, 49 | ); 50 | } 51 | 52 | /// Shows default Dialog with some customizations 53 | void showDefault({ 54 | // title 55 | String? title, 56 | Color? titleColor, 57 | double? titleSize, 58 | FontWeight? titleWeight, 59 | // message 60 | String? message, 61 | Color? messageColor, 62 | double? messageSize, 63 | FontWeight? messageWeight, 64 | // button one 65 | String? buttonOneText = '', 66 | Color? buttonOneTextColor, 67 | double? buttonOneTextSize, 68 | FontWeight? buttonOneTextWeight, 69 | Color? buttonOneColor, 70 | RadiusPlus? buttonOneRadius, 71 | Function()? buttonOneCallback, 72 | // buttonTwo 73 | String? buttonTwoText = '', 74 | Color? buttonTwoTextColor, 75 | double? buttonTwoTextSize, 76 | FontWeight? buttonTwoTextWeight, 77 | Color? buttonTwoColor, 78 | RadiusPlus? buttonTwoRadius, 79 | Function()? buttonTwoCallback, 80 | // others 81 | double? buttonsHeight, 82 | EdgeInsetsGeometry? padding, 83 | Color? barrierColor, 84 | bool barrierDismissible = true, 85 | bool closeKeyboardWhenOpen = true, 86 | RadiusPlus? radius, 87 | BorderPlus? border, 88 | double elevation = 1, 89 | double elementsSpacing = 16, 90 | double? screenHorizontalMargin, 91 | }) { 92 | if (closeKeyboardWhenOpen == true) { 93 | utilsPlus.closeKeyboard(); 94 | } 95 | showDialog( 96 | context: navigatorPlus.currentContext!, 97 | barrierColor: barrierColor, 98 | barrierDismissible: buttonOneText == null ? true : barrierDismissible, 99 | builder: (context) { 100 | Widget? buttonsContent; 101 | if (buttonOneText!.isNotNullOrEmpty && 102 | buttonTwoText!.isNotNullOrEmpty) { 103 | buttonsContent = Row( 104 | mainAxisAlignment: MainAxisAlignment.center, 105 | children: [ 106 | Expanded( 107 | child: _createButton( 108 | buttonOneText, 109 | buttonOneTextColor, 110 | buttonOneTextSize, 111 | buttonOneTextWeight, 112 | buttonsHeight, 113 | buttonOneColor, 114 | buttonOneRadius, 115 | buttonOneCallback, 116 | ), 117 | ), 118 | SizedBox( 119 | width: elementsSpacing, 120 | ), 121 | Expanded( 122 | child: _createButton( 123 | buttonTwoText, 124 | buttonTwoTextColor, 125 | buttonTwoTextSize, 126 | buttonTwoTextWeight, 127 | buttonsHeight, 128 | buttonTwoColor, 129 | buttonTwoRadius, 130 | buttonTwoCallback, 131 | ), 132 | ) 133 | ], 134 | ); 135 | } else if (buttonOneText.isNotNullOrEmpty) { 136 | buttonsContent = _createButton( 137 | buttonOneText, 138 | buttonOneTextColor, 139 | buttonOneTextSize, 140 | buttonOneTextWeight, 141 | buttonsHeight, 142 | buttonOneColor, 143 | buttonOneRadius, 144 | buttonOneCallback, 145 | ); 146 | } else if (buttonTwoText!.isNotNullOrEmpty) { 147 | buttonsContent = _createButton( 148 | buttonTwoText, 149 | buttonTwoTextColor, 150 | buttonTwoTextSize, 151 | buttonTwoTextWeight, 152 | buttonsHeight, 153 | buttonTwoColor, 154 | buttonTwoRadius, 155 | buttonTwoCallback, 156 | ); 157 | } 158 | 159 | TextPlus? titleWidget; 160 | if (title != null) { 161 | titleWidget = TextPlus( 162 | title, 163 | color: titleColor ?? Colors.black, 164 | fontSize: titleSize ?? 20, 165 | fontWeight: titleWeight ?? FontWeight.w700, 166 | textAlign: TextAlign.center, 167 | textOverflow: TextOverflow.ellipsis, 168 | ); 169 | } 170 | 171 | TextPlus? messageWidget; 172 | if (message != null) { 173 | messageWidget = TextPlus( 174 | message, 175 | color: messageColor ?? Colors.grey, 176 | fontSize: messageSize ?? 16, 177 | fontWeight: messageWeight ?? FontWeight.normal, 178 | textAlign: TextAlign.center, 179 | // textOverflow: TextOverflow.ellipsis, 180 | ); 181 | } 182 | 183 | var dialogContent = Padding( 184 | padding: padding ?? EdgeInsets.all(16), 185 | child: Column( 186 | mainAxisSize: MainAxisSize.min, 187 | crossAxisAlignment: CrossAxisAlignment.stretch, 188 | mainAxisAlignment: MainAxisAlignment.center, 189 | children: [ 190 | titleWidget ?? SizedBox.shrink(), 191 | messageWidget != null 192 | ? SizedBox( 193 | height: elementsSpacing, 194 | ) 195 | : SizedBox.shrink(), 196 | messageWidget ?? SizedBox.shrink(), 197 | buttonsContent != null 198 | ? SizedBox( 199 | height: elementsSpacing, 200 | ) 201 | : SizedBox.shrink(), 202 | buttonsContent ?? SizedBox.shrink(), 203 | ], 204 | ), 205 | ); 206 | return _createDialog( 207 | dialogContent, 208 | elevation, 209 | radius ?? RadiusPlus.all(20), 210 | border, 211 | screenHorizontalMargin, 212 | ); 213 | }, 214 | ); 215 | } 216 | 217 | Widget _createDialog( 218 | Widget child, 219 | double elevation, 220 | RadiusPlus? radius, 221 | BorderPlus? border, 222 | double? screenHorizontalMargin, 223 | ) { 224 | return Dialog( 225 | child: ClipRRect( 226 | borderRadius: radius?.toBorderRadius ?? BorderRadius.zero, 227 | child: child, 228 | ), 229 | elevation: elevation, 230 | shape: RoundedRectangleBorder( 231 | borderRadius: radius?.toBorderRadius ?? BorderRadius.zero, 232 | side: border?.toBorderSide ?? BorderSide.none, 233 | ), 234 | insetPadding: EdgeInsets.symmetric( 235 | horizontal: screenHorizontalMargin ?? 24, 236 | ), 237 | ); 238 | } 239 | 240 | ButtonPlus _createButton( 241 | String? buttonText, 242 | Color? buttonTextColor, 243 | double? buttonTextSize, 244 | FontWeight? buttonTextWeight, 245 | double? buttonsHeight, 246 | Color? buttonColor, 247 | RadiusPlus? buttonRadius, 248 | Function()? buttonCallback, 249 | ) { 250 | return ButtonPlus( 251 | child: TextPlus( 252 | buttonText, 253 | color: buttonTextColor ?? Colors.white, 254 | fontSize: buttonTextSize ?? 18, 255 | fontWeight: buttonTextWeight ?? FontWeight.w700, 256 | ), 257 | height: buttonsHeight ?? 50, 258 | color: buttonColor ?? Colors.blue, 259 | radius: buttonRadius ?? RadiusPlus.all(12), 260 | onPressed: buttonCallback, 261 | ); 262 | } 263 | } 264 | -------------------------------------------------------------------------------- /lib/src/extensions/src/string_exntension_plus.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'package:diacritic/diacritic.dart'; 3 | import 'package:intl/intl.dart'; 4 | 5 | extension StringExtensionPlus on String { 6 | /// Checks whether string is empty or null 7 | // bool get isNullOrEmpty { 8 | // return isNotEmpty; 9 | // } 10 | 11 | /// Checks whether string is not empty or null 12 | bool get isNotNullOrEmpty { 13 | return isNotEmpty; 14 | } 15 | 16 | /// Get first letter of string 17 | String? get firstLetter { 18 | if (isNotNullOrEmpty) { 19 | return this[0].toUpperCase(); 20 | } else { 21 | return null; 22 | } 23 | } 24 | 25 | /// Get first word of string 26 | String? get firstWord { 27 | if (isNotNullOrEmpty) { 28 | var words = split(' '); 29 | if (words.length > 0) { 30 | return words[0]; 31 | } else { 32 | return this; 33 | } 34 | } else { 35 | return ''; 36 | } 37 | } 38 | 39 | /// Convert String to base64 40 | String? get toBase64 { 41 | if (isNotNullOrEmpty) { 42 | Codec stringToBase64 = utf8.fuse(base64); 43 | return stringToBase64.encode(this); 44 | } else { 45 | return null; 46 | } 47 | } 48 | 49 | /// Convert base64 to String 50 | String? get fromBase64 { 51 | if (isNotNullOrEmpty) { 52 | var stringToBase64 = utf8.fuse(base64); 53 | return stringToBase64.decode(this); 54 | } else { 55 | return null; 56 | } 57 | } 58 | 59 | /// Remove special characters from the String 60 | String? get cleanString { 61 | if (isNotNullOrEmpty) { 62 | return replaceAll(RegExp(r'[^\w\s]+'), ''); 63 | } else { 64 | return null; 65 | } 66 | } 67 | 68 | /// Remove special characters and spaces from the String 69 | String? get cleanStringAndSpaces { 70 | if (isNotNullOrEmpty) { 71 | return replaceAll(RegExp(r'[^\w\s]+'), '').replaceAll(' ', ''); 72 | } else { 73 | return null; 74 | } 75 | } 76 | 77 | /// Checks whether the string is an e-mail 78 | bool get isEmail { 79 | return _checkRegex( 80 | r'^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$', 81 | ); 82 | } 83 | 84 | /// Checks whether the string is an CPF (Brazil) 85 | bool get isCpf { 86 | if (isNotNullOrEmpty) { 87 | var sanitizedCPF = 88 | replaceAll(RegExp(r'\.|-'), '').split('').map(int.parse).toList(); 89 | return !_blacklistedCPF(sanitizedCPF.join()) && 90 | sanitizedCPF[9] == 91 | _gerarDigitoVerificador(sanitizedCPF.getRange(0, 9).toList()) && 92 | sanitizedCPF[10] == 93 | _gerarDigitoVerificador(sanitizedCPF.getRange(0, 10).toList()); 94 | } else { 95 | return false; 96 | } 97 | } 98 | 99 | bool _blacklistedCPF(String cpf) { 100 | return cpf == '00000000000' || 101 | cpf == '11111111111' || 102 | cpf == '22222222222' || 103 | cpf == '33333333333' || 104 | cpf == '44444444444' || 105 | cpf == '55555555555' || 106 | cpf == '66666666666' || 107 | cpf == '77777777777' || 108 | cpf == '88888888888' || 109 | cpf == '99999999999'; 110 | } 111 | 112 | int _gerarDigitoVerificador(List digits) { 113 | var baseNumber = 0; 114 | for (var i = 0; i < digits.length; i++) { 115 | baseNumber += digits[i] * ((digits.length + 1) - i); 116 | } 117 | var verificationDigit = baseNumber * 10 % 11; 118 | return verificationDigit >= 10 ? 0 : verificationDigit; 119 | } 120 | 121 | /// Checks whether the string is an cellphone (Brazil) 122 | bool get isCelular { 123 | return _checkRegex(r'^\([1-9]{2}\) [0-9]{5}\-[0-9]{4}$'); 124 | } 125 | 126 | /// Checks whether the string is an phone number (Brazil) 127 | bool get isTelefone { 128 | return _checkRegex(r'^\([1-9]{2}\) [0-9]{4}\-[0-9]{4}$'); 129 | } 130 | 131 | /// Compare to another String with caseSensitive or not 132 | bool compareStrings(String text, {bool? caseSensitive}) { 133 | if (isEmpty && text.isEmpty) { 134 | return true; 135 | } else { 136 | var originalStr = cleanString?.cleanDiacritics; 137 | var compareStr = text.cleanString?.cleanDiacritics; 138 | if (originalStr == null || compareStr == null) { 139 | return false; 140 | } 141 | if (caseSensitive == false) { 142 | originalStr = originalStr.toLowerCase(); 143 | compareStr = compareStr.toLowerCase(); 144 | } 145 | return originalStr.compareTo(compareStr) == 0; 146 | } 147 | } 148 | 149 | /// Containes to another String with caseSensitive or not 150 | bool containesStrings(String text, {bool? caseSensitive}) { 151 | if (isEmpty && text.isEmpty) { 152 | return true; 153 | } else { 154 | var originalStr = cleanString?.cleanDiacritics; 155 | var compareStr = text.cleanString?.cleanDiacritics; 156 | if (originalStr == null || compareStr == null) { 157 | return false; 158 | } 159 | if (caseSensitive == false) { 160 | originalStr = originalStr.toLowerCase(); 161 | compareStr = compareStr.toLowerCase(); 162 | } 163 | return originalStr.contains(compareStr) == 0; 164 | } 165 | } 166 | 167 | /// Remove diacritics from the String 168 | /// Remove acentos da String 169 | String? get cleanDiacritics { 170 | if (isNotNullOrEmpty) { 171 | return removeDiacritics(this); 172 | } else { 173 | return null; 174 | } 175 | } 176 | 177 | /// Capitalize first word from the String 178 | String? get capitalizeFirstWord { 179 | if (isNotNullOrEmpty) { 180 | var input = toLowerCase(); 181 | return input[0].toUpperCase() + input.substring(1); 182 | } else { 183 | return null; 184 | } 185 | } 186 | 187 | /// Capitalize all words from the String 188 | String? get capitalizeAllWords { 189 | if (isNotNullOrEmpty) { 190 | var input = toLowerCase(); 191 | var words = input.split(' '); 192 | var capitalized = words.map((word) { 193 | if (word.isEmpty) { 194 | return ''; 195 | } 196 | return word[0].toUpperCase() + word.substring(1); 197 | }).join(' '); 198 | return capitalized; 199 | } else { 200 | return null; 201 | } 202 | } 203 | 204 | /// Transfor String to DateTime 205 | DateTime? toDate({required String format}) { 206 | if (isNotNullOrEmpty) { 207 | return DateFormat(format).parse(this); 208 | } else { 209 | return null; 210 | } 211 | } 212 | 213 | /// Set custom mask to String 214 | String? setMask({required String mask}) { 215 | if (isNotNullOrEmpty) { 216 | var cleanText = cleanStringAndSpaces; 217 | var maskItemCount = 0; 218 | var maskedString = ''; 219 | for (var i = 0; i < mask.length; i++) { 220 | if (mask[i] == '#') { 221 | maskedString += cleanText![i - maskItemCount]; 222 | } else { 223 | maskedString += mask[i]; 224 | maskItemCount++; 225 | } 226 | } 227 | return maskedString; 228 | } else { 229 | return null; 230 | } 231 | } 232 | 233 | /// Checks whether a String is a number 234 | bool get isNum { 235 | if (isNotNullOrEmpty) { 236 | var source = trim(); 237 | var numberValue = int.tryParse(source) ?? 238 | double.tryParse(source) ?? 239 | num.tryParse(source); 240 | return numberValue != null; 241 | } else { 242 | return false; 243 | } 244 | } 245 | 246 | /// Checks whether a String is a bool 247 | bool get isBool { 248 | if (isNotNullOrEmpty) { 249 | return (this == 'true' || this == 'false'); 250 | } else { 251 | return false; 252 | } 253 | } 254 | 255 | /// Checks whether a String is a dateTime 256 | // bool get isDateTime { 257 | // // return _checkRegex(r"^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}:\d{2}.\d{3}Z?$"); 258 | // } 259 | 260 | /// Checks whether a String is a dateTime 261 | bool isDateTime({required String format}) { 262 | if (format.isNotNullOrEmpty || isNotNullOrEmpty) { 263 | try { 264 | var dateTime = toDate(format: format); 265 | if (dateTime != null) { 266 | return true; 267 | } else { 268 | return false; 269 | } 270 | } on Exception catch (e) { 271 | print(e); 272 | return false; 273 | } 274 | } else { 275 | return false; 276 | } 277 | } 278 | 279 | /// Checks whether a String is a url 280 | bool get isURL { 281 | return _checkRegex( 282 | r"^((((H|h)(T|t)|(F|f))(T|t)(P|p)((S|s)?))\://)?(www.|[a-zA-Z0-9].)[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,6}(\:[0-9]{1,5})*(/($|[a-zA-Z0-9\.\,\;\?\'\\\+&%\$#\=~_\-]+))*$", 283 | ); 284 | } 285 | 286 | bool _checkRegex(String regex) { 287 | if (isNotNullOrEmpty) { 288 | return RegExp(regex).hasMatch(this); 289 | } else { 290 | return false; 291 | } 292 | } 293 | } 294 | -------------------------------------------------------------------------------- /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 | sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" 9 | url: "https://pub.dev" 10 | source: hosted 11 | version: "2.11.0" 12 | boolean_selector: 13 | dependency: transitive 14 | description: 15 | name: boolean_selector 16 | sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" 17 | url: "https://pub.dev" 18 | source: hosted 19 | version: "2.1.1" 20 | characters: 21 | dependency: transitive 22 | description: 23 | name: characters 24 | sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" 25 | url: "https://pub.dev" 26 | source: hosted 27 | version: "1.3.0" 28 | clock: 29 | dependency: transitive 30 | description: 31 | name: clock 32 | sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf 33 | url: "https://pub.dev" 34 | source: hosted 35 | version: "1.1.1" 36 | collection: 37 | dependency: transitive 38 | description: 39 | name: collection 40 | sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 41 | url: "https://pub.dev" 42 | source: hosted 43 | version: "1.17.2" 44 | diacritic: 45 | dependency: "direct main" 46 | description: 47 | name: diacritic 48 | sha256: c09a420e737dc036122121fea9f774767e95068f34a17894ee9db30c5bda3075 49 | url: "https://pub.dev" 50 | source: hosted 51 | version: "0.1.3" 52 | fake_async: 53 | dependency: transitive 54 | description: 55 | name: fake_async 56 | sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" 57 | url: "https://pub.dev" 58 | source: hosted 59 | version: "1.3.1" 60 | ffi: 61 | dependency: transitive 62 | description: 63 | name: ffi 64 | sha256: "35d0f481d939de0d640b3db9a7aa36a52cd22054a798a73b4f50bdad5ce12678" 65 | url: "https://pub.dev" 66 | source: hosted 67 | version: "1.1.2" 68 | file: 69 | dependency: transitive 70 | description: 71 | name: file 72 | sha256: b69516f2c26a5bcac4eee2e32512e1a5205ab312b3536c1c1227b2b942b5f9ad 73 | url: "https://pub.dev" 74 | source: hosted 75 | version: "6.1.2" 76 | flutter: 77 | dependency: "direct main" 78 | description: flutter 79 | source: sdk 80 | version: "0.0.0" 81 | flutter_test: 82 | dependency: "direct dev" 83 | description: flutter 84 | source: sdk 85 | version: "0.0.0" 86 | flutter_web_plugins: 87 | dependency: transitive 88 | description: flutter 89 | source: sdk 90 | version: "0.0.0" 91 | intl: 92 | dependency: "direct main" 93 | description: 94 | name: intl 95 | sha256: "910f85bce16fb5c6f614e117efa303e85a1731bb0081edf3604a2ae6e9a3cc91" 96 | url: "https://pub.dev" 97 | source: hosted 98 | version: "0.17.0" 99 | matcher: 100 | dependency: transitive 101 | description: 102 | name: matcher 103 | sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" 104 | url: "https://pub.dev" 105 | source: hosted 106 | version: "0.12.16" 107 | material_color_utilities: 108 | dependency: transitive 109 | description: 110 | name: material_color_utilities 111 | sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" 112 | url: "https://pub.dev" 113 | source: hosted 114 | version: "0.5.0" 115 | meta: 116 | dependency: transitive 117 | description: 118 | name: meta 119 | sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" 120 | url: "https://pub.dev" 121 | source: hosted 122 | version: "1.9.1" 123 | path: 124 | dependency: "direct main" 125 | description: 126 | name: path 127 | sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" 128 | url: "https://pub.dev" 129 | source: hosted 130 | version: "1.8.3" 131 | path_provider_linux: 132 | dependency: transitive 133 | description: 134 | name: path_provider_linux 135 | sha256: "938d2b6591587bcb009d2109a6ea464fd8fb2a75dc6423171b0d0afb1d27c708" 136 | url: "https://pub.dev" 137 | source: hosted 138 | version: "2.0.0" 139 | path_provider_platform_interface: 140 | dependency: transitive 141 | description: 142 | name: path_provider_platform_interface 143 | sha256: c2af5a8a6369992d915f8933dfc23172071001359d17896e83db8be57db8a397 144 | url: "https://pub.dev" 145 | source: hosted 146 | version: "2.0.1" 147 | path_provider_windows: 148 | dependency: transitive 149 | description: 150 | name: path_provider_windows 151 | sha256: "99bb2d003df56a2a846e23f716bbf713a1d36d3e2a7d7e99ca4b01aeae80045a" 152 | url: "https://pub.dev" 153 | source: hosted 154 | version: "2.0.1" 155 | pedantic: 156 | dependency: "direct dev" 157 | description: 158 | name: pedantic 159 | sha256: "67fc27ed9639506c856c840ccce7594d0bdcd91bc8d53d6e52359449a1d50602" 160 | url: "https://pub.dev" 161 | source: hosted 162 | version: "1.11.1" 163 | platform: 164 | dependency: transitive 165 | description: 166 | name: platform 167 | sha256: ebc79f16b5f6b609aad4a5e63447d4795d16f7adee46e93ed03200848c006735 168 | url: "https://pub.dev" 169 | source: hosted 170 | version: "3.0.0" 171 | plugin_platform_interface: 172 | dependency: transitive 173 | description: 174 | name: plugin_platform_interface 175 | sha256: "5aadc2af7cd403ad0b95ef654c3e628517f4cae9682b4229a66caf9df71844d2" 176 | url: "https://pub.dev" 177 | source: hosted 178 | version: "2.0.1" 179 | process: 180 | dependency: transitive 181 | description: 182 | name: process 183 | sha256: dc3c073b5bc0db4e0f3dbc6b69f8e9cf2f336dafb3db996242ebdacf94c295dd 184 | url: "https://pub.dev" 185 | source: hosted 186 | version: "4.2.1" 187 | shared_preferences: 188 | dependency: "direct main" 189 | description: 190 | name: shared_preferences 191 | sha256: "5c34bd1fd5ddfca85766659b1b82342d8b047ceb3ecf34f6dd439640a41ccff6" 192 | url: "https://pub.dev" 193 | source: hosted 194 | version: "2.0.6" 195 | shared_preferences_linux: 196 | dependency: transitive 197 | description: 198 | name: shared_preferences_linux 199 | sha256: "33fc7c6ced70d226645a9612132fbff9890805df4edd34f30840e7e738866fee" 200 | url: "https://pub.dev" 201 | source: hosted 202 | version: "2.0.0" 203 | shared_preferences_macos: 204 | dependency: transitive 205 | description: 206 | name: shared_preferences_macos 207 | sha256: "5d2bad07b196b6ad4cf21af6f7197a87264ef569199502b9352f76e5054f06ae" 208 | url: "https://pub.dev" 209 | source: hosted 210 | version: "2.0.0" 211 | shared_preferences_platform_interface: 212 | dependency: transitive 213 | description: 214 | name: shared_preferences_platform_interface 215 | sha256: "992f0fdc46d0a3c0ac2e5859f2de0e577bbe51f78a77ee8f357cbe626a2ad32d" 216 | url: "https://pub.dev" 217 | source: hosted 218 | version: "2.0.0" 219 | shared_preferences_web: 220 | dependency: transitive 221 | description: 222 | name: shared_preferences_web 223 | sha256: "09b72ec530a1b1f26cdbec6b138f980d97d4d86ebb86dbf6365369fbd4bb05c8" 224 | url: "https://pub.dev" 225 | source: hosted 226 | version: "2.0.0" 227 | shared_preferences_windows: 228 | dependency: transitive 229 | description: 230 | name: shared_preferences_windows 231 | sha256: "76c54a0148780d779a3fe332ece9ba8ad2c9dd0bc717ee7fce58bd06b5e8118f" 232 | url: "https://pub.dev" 233 | source: hosted 234 | version: "2.0.0" 235 | sky_engine: 236 | dependency: transitive 237 | description: flutter 238 | source: sdk 239 | version: "0.0.99" 240 | source_span: 241 | dependency: transitive 242 | description: 243 | name: source_span 244 | sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" 245 | url: "https://pub.dev" 246 | source: hosted 247 | version: "1.10.0" 248 | stack_trace: 249 | dependency: transitive 250 | description: 251 | name: stack_trace 252 | sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 253 | url: "https://pub.dev" 254 | source: hosted 255 | version: "1.11.0" 256 | stream_channel: 257 | dependency: transitive 258 | description: 259 | name: stream_channel 260 | sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" 261 | url: "https://pub.dev" 262 | source: hosted 263 | version: "2.1.1" 264 | string_scanner: 265 | dependency: transitive 266 | description: 267 | name: string_scanner 268 | sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" 269 | url: "https://pub.dev" 270 | source: hosted 271 | version: "1.2.0" 272 | term_glyph: 273 | dependency: transitive 274 | description: 275 | name: term_glyph 276 | sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 277 | url: "https://pub.dev" 278 | source: hosted 279 | version: "1.2.1" 280 | test_api: 281 | dependency: transitive 282 | description: 283 | name: test_api 284 | sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" 285 | url: "https://pub.dev" 286 | source: hosted 287 | version: "0.6.0" 288 | vector_math: 289 | dependency: transitive 290 | description: 291 | name: vector_math 292 | sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" 293 | url: "https://pub.dev" 294 | source: hosted 295 | version: "2.1.4" 296 | web: 297 | dependency: transitive 298 | description: 299 | name: web 300 | sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 301 | url: "https://pub.dev" 302 | source: hosted 303 | version: "0.1.4-beta" 304 | win32: 305 | dependency: transitive 306 | description: 307 | name: win32 308 | sha256: "309dff75a557c8bacaa3d0958c2f800d0b452c22998544f147ef99aae61b66f1" 309 | url: "https://pub.dev" 310 | source: hosted 311 | version: "2.2.5" 312 | xdg_directories: 313 | dependency: transitive 314 | description: 315 | name: xdg_directories 316 | sha256: "0186b3f2d66be9a12b0295bddcf8b6f8c0b0cc2f85c6287344e2a6366bc28457" 317 | url: "https://pub.dev" 318 | source: hosted 319 | version: "0.2.0" 320 | sdks: 321 | dart: ">=3.1.0-185.0.dev <4.0.0" 322 | flutter: ">=1.20.0" 323 | -------------------------------------------------------------------------------- /example/lib/src/screens/home_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_plus/flutter_plus.dart'; 3 | import 'package:url_launcher/url_launcher.dart'; 4 | 5 | import '../widgets/custom_widget.dart'; 6 | 7 | import 'button_plus_screen.dart'; 8 | import 'compare_widget_screen.dart'; 9 | import 'container_plus_screen.dart'; 10 | import 'navigator_plus_screen.dart'; 11 | import 'rich_text_plus_screen.dart'; 12 | import 'text_field_plus_screen.dart'; 13 | import 'text_plus_screen.dart'; 14 | 15 | class HomeScreen extends StatelessWidget { 16 | @override 17 | Widget build(BuildContext context) { 18 | return Scaffold( 19 | appBar: AppBar( 20 | title: TextPlus( 21 | 'FlutterPlus Example', 22 | color: Colors.white, 23 | fontWeight: FontWeight.bold, 24 | ), 25 | backgroundColor: Colors.red, 26 | actions: [ 27 | _buildInfoButton(), 28 | ], 29 | ), 30 | body: _buildBody(), 31 | ); 32 | } 33 | 34 | Widget _buildInfoButton() { 35 | return ButtonPlus( 36 | child: Icon( 37 | Icons.info_outline, 38 | color: Colors.white, 39 | ), 40 | onPressed: () { 41 | dialogPlus.showDefault( 42 | title: 'FlutterPlus', 43 | message: 'Developed by Gabriel Braga.', 44 | buttonOneText: 'OK', 45 | buttonOneColor: Colors.black, 46 | buttonOneCallback: () { 47 | navigatorPlus.back(); 48 | }, 49 | ); 50 | }, 51 | ); 52 | } 53 | 54 | Widget _buildBody() { 55 | return ListView( 56 | padding: EdgeInsets.all(24), 57 | children: [ 58 | // _buildButton( 59 | // 'SaveData', 60 | // Colors.purple, 61 | // () { 62 | // localStoragePlus.write('flutter_plus_key', 63 | // DateTime.now().format('dd/MM/yyyy HH:mm:ss')); 64 | // }, 65 | // ), 66 | // _buildButton( 67 | // 'GetData', 68 | // Colors.purple, 69 | // () async { 70 | // var data = await localStoragePlus.read('flutter_plus_key'); 71 | // print(data); 72 | // }, 73 | // ), 74 | _buildButton( 75 | 'ContainerPlus', 76 | Colors.redAccent, 77 | () { 78 | navigatorPlus.show(ContainerPlusScreen()); 79 | }, 80 | ), 81 | _buildButton( 82 | 'ButtonPlus', 83 | Colors.redAccent, 84 | () { 85 | navigatorPlus.show(ButtonPlusScreen()); 86 | }, 87 | ), 88 | _buildButton( 89 | 'TextFieldPlus', 90 | Colors.redAccent, 91 | () { 92 | navigatorPlus.show(TextFieldPlusScreen()); 93 | }, 94 | ), 95 | _buildButton( 96 | 'TextPlus', 97 | Colors.redAccent, 98 | () { 99 | navigatorPlus.show(TextPlusScreen()); 100 | }, 101 | ), 102 | _buildButton( 103 | 'RichTextPlus', 104 | Colors.redAccent, 105 | () { 106 | navigatorPlus.show(RichTextPlusScreen()); 107 | }, 108 | ), 109 | Divider( 110 | color: Colors.black, 111 | ), 112 | Row( 113 | children: [ 114 | Expanded( 115 | child: _buildButton( 116 | 'NavigatorPlus:\nshowModal()', 117 | Colors.blueAccent, 118 | () { 119 | navigatorPlus.showModal(NavigatorPlusScreen()); 120 | }, 121 | ), 122 | ), 123 | SizedBox( 124 | width: 8, 125 | ), 126 | Expanded( 127 | child: _buildButton( 128 | 'NavigatorPlus:\nshow()', 129 | Colors.blueAccent, 130 | () { 131 | navigatorPlus.show(NavigatorPlusScreen()); 132 | }, 133 | ), 134 | ), 135 | ], 136 | ), 137 | Row( 138 | children: [ 139 | Expanded( 140 | child: _buildButton( 141 | 'SnackBarPlus:\nshowText()', 142 | Colors.blueAccent, 143 | () { 144 | snackBarPlus.showText( 145 | 'FlutterPlus', 146 | textColor: Colors.white, 147 | fontSize: 18, 148 | fontWeight: FontWeight.bold, 149 | backgroundColor: Colors.green, 150 | ); 151 | }, 152 | ), 153 | ), 154 | SizedBox( 155 | width: 8, 156 | ), 157 | Expanded( 158 | child: _buildButton( 159 | 'SnackBarPlus:\nshow()', 160 | Colors.blueAccent, 161 | () { 162 | snackBarPlus.show( 163 | backgroundColor: Colors.green, 164 | child: Row( 165 | mainAxisAlignment: MainAxisAlignment.center, 166 | children: [ 167 | Icon( 168 | Icons.star, 169 | color: Colors.yellow, 170 | ), 171 | SizedBox( 172 | width: 8, 173 | ), 174 | TextPlus( 175 | 'FlutterPlus!', 176 | color: Colors.white, 177 | fontSize: 18, 178 | fontWeight: FontWeight.bold, 179 | ), 180 | SizedBox( 181 | width: 8, 182 | ), 183 | Icon( 184 | Icons.star, 185 | color: Colors.yellow, 186 | ), 187 | ], 188 | ), 189 | ); 190 | }, 191 | ), 192 | ) 193 | ], 194 | ), 195 | Row( 196 | children: [ 197 | Expanded( 198 | child: _buildButton( 199 | 'DialogPlus:\nshowDefault()', 200 | Colors.blueAccent, 201 | () { 202 | const url = 'https://github.com/gbmiranda/flutter_plus'; 203 | dialogPlus.showDefault( 204 | title: 'FlutterPlus', 205 | message: url, 206 | elementsSpacing: 16, 207 | buttonOneText: 'Close', 208 | buttonOneColor: Colors.red, 209 | buttonOneCallback: () { 210 | navigatorPlus.back(); 211 | }, 212 | buttonTwoText: 'Open', 213 | buttonTwoCallback: () async { 214 | if (await canLaunch(url)) { 215 | await launch(url); 216 | } else { 217 | print('Could not launch $url'); 218 | } 219 | }, 220 | ); 221 | }, 222 | ), 223 | ), 224 | SizedBox( 225 | width: 8, 226 | ), 227 | Expanded( 228 | child: _buildButton( 229 | 'DialogPlus:\nshow()', 230 | Colors.blueAccent, 231 | () { 232 | dialogPlus.show( 233 | child: CustomWidget(), 234 | radius: RadiusPlus.all(20), 235 | closeKeyboardWhenOpen: true, 236 | ); 237 | }, 238 | ), 239 | ) 240 | ], 241 | ), 242 | _buildButton( 243 | 'BottomSheetPlus', 244 | Colors.blueAccent, 245 | () { 246 | bottomSheetPlus.show( 247 | child: CustomWidget(), 248 | radius: RadiusPlus.top(20), 249 | heightPercentScreen: 0.3, 250 | ); 251 | }, 252 | ), 253 | Divider( 254 | color: Colors.black, 255 | ), 256 | _buildButton( 257 | 'Compare Widgets', 258 | Colors.orange, 259 | () { 260 | navigatorPlus.show(CompareWidgetScreen()); 261 | }, 262 | ), 263 | _buildButton( 264 | 'Open complete documentation', 265 | Colors.green, 266 | _openDocSite, 267 | ), 268 | ], 269 | ); 270 | } 271 | 272 | _openDocSite() async { 273 | const url = 274 | 'https://github.com/gbmiranda/flutter_plus/blob/master/README.md'; 275 | if (await canLaunch(url)) { 276 | await launch(url); 277 | } else { 278 | print('Could not launch $url'); 279 | } 280 | } 281 | 282 | Widget _buildButton(String title, Color color, Function() onPressed) { 283 | return ButtonPlus( 284 | margin: EdgeInsets.symmetric(vertical: 8), 285 | padding: EdgeInsets.symmetric(horizontal: 8), 286 | radius: RadiusPlus.all(8), 287 | height: 50, 288 | child: TextPlus( 289 | title, 290 | color: Colors.white, 291 | fontWeight: FontWeight.bold, 292 | textAlign: TextAlign.center, 293 | ), 294 | color: color, 295 | onPressed: onPressed, 296 | ); 297 | } 298 | 299 | // _atributos() { 300 | // BorderPlus( 301 | // color: Colors.black, 302 | // style: BorderStyle.solid, 303 | // width: 2.0, 304 | // ); 305 | 306 | // GradientPlus.linear( 307 | // colors: [Colors.black, Colors.white], 308 | // begin: Alignment.centerLeft, 309 | // end: Alignment.centerRight, 310 | // stops: [0.2, 0.8], 311 | // ); 312 | 313 | // GradientPlus.radial( 314 | // colors: [Colors.black, Colors.white], 315 | // center: Alignment.centerLeft, 316 | // focal: Alignment.bottomCenter, 317 | // focalRadius: 1.5, 318 | // radius: 4.5, 319 | // stops: [0.3, 0.7], 320 | // ); 321 | 322 | // GradientPlus.sweep( 323 | // colors: [Colors.black, Colors.white], 324 | // center: Alignment.centerLeft, 325 | // startAngle: 1.5, 326 | // endAngle: 3.2, 327 | // stops: [0.5, 0.8], 328 | // ); 329 | 330 | // InnerShadowPlus( 331 | // color: Colors.red, 332 | // blur: 10.0, 333 | // moveDown: 4.5, 334 | // moveRight: 2.5, 335 | // opacity: 0.5, 336 | // ); 337 | 338 | // ShadowPlus( 339 | // color: Colors.red, 340 | // blur: 10.0, 341 | // spread: 2.5, 342 | // moveDown: 4.5, 343 | // moveRight: 2.5, 344 | // opacity: 0.5, 345 | // ); 346 | 347 | // RadiusPlus.all(12.0); 348 | 349 | // RadiusPlus.bottom(12.0); 350 | 351 | // RadiusPlus.only( 352 | // topLeft: 12.0, 353 | // topRight: 12.0, 354 | // bottomLeft: 8.0, 355 | // bottomRight: 8.0, 356 | // ); 357 | 358 | // RadiusPlus.top(12.0); 359 | 360 | // SkeletonPlus.custom( 361 | // enabled: true, 362 | // baseColor: Colors.black87, 363 | // highlightColor: Colors.black26, 364 | // duration: Duration( 365 | // milliseconds: 500, 366 | // ), 367 | // showBorders: false, 368 | // showShadows: false, 369 | // ); 370 | 371 | // TextDecorationPlus( 372 | // color: Colors.red, 373 | // decorationStyle: TextDecorationStyle.dashed, 374 | // decorationThickness: 0.5, 375 | // ); 376 | // } 377 | } 378 | -------------------------------------------------------------------------------- /example/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 | sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" 9 | url: "https://pub.dev" 10 | source: hosted 11 | version: "2.11.0" 12 | boolean_selector: 13 | dependency: transitive 14 | description: 15 | name: boolean_selector 16 | sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" 17 | url: "https://pub.dev" 18 | source: hosted 19 | version: "2.1.1" 20 | characters: 21 | dependency: transitive 22 | description: 23 | name: characters 24 | sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" 25 | url: "https://pub.dev" 26 | source: hosted 27 | version: "1.3.0" 28 | clock: 29 | dependency: transitive 30 | description: 31 | name: clock 32 | sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf 33 | url: "https://pub.dev" 34 | source: hosted 35 | version: "1.1.1" 36 | collection: 37 | dependency: transitive 38 | description: 39 | name: collection 40 | sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 41 | url: "https://pub.dev" 42 | source: hosted 43 | version: "1.17.2" 44 | cupertino_icons: 45 | dependency: "direct main" 46 | description: 47 | name: cupertino_icons 48 | sha256: "486b7bc707424572cdf7bd7e812a0c146de3fd47ecadf070254cc60383f21dd8" 49 | url: "https://pub.dev" 50 | source: hosted 51 | version: "1.0.3" 52 | diacritic: 53 | dependency: transitive 54 | description: 55 | name: diacritic 56 | sha256: c09a420e737dc036122121fea9f774767e95068f34a17894ee9db30c5bda3075 57 | url: "https://pub.dev" 58 | source: hosted 59 | version: "0.1.3" 60 | fake_async: 61 | dependency: transitive 62 | description: 63 | name: fake_async 64 | sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" 65 | url: "https://pub.dev" 66 | source: hosted 67 | version: "1.3.1" 68 | ffi: 69 | dependency: transitive 70 | description: 71 | name: ffi 72 | sha256: d97fffd9d86f3dccc7a9059128b468a99320c69007cc9d41a3a1bda07d4e86dc 73 | url: "https://pub.dev" 74 | source: hosted 75 | version: "1.0.0" 76 | file: 77 | dependency: transitive 78 | description: 79 | name: file 80 | sha256: "9fd2163d866769f60f4df8ac1dc59f52498d810c356fe78022e383dd3c57c0e1" 81 | url: "https://pub.dev" 82 | source: hosted 83 | version: "6.1.0" 84 | flutter: 85 | dependency: "direct main" 86 | description: flutter 87 | source: sdk 88 | version: "0.0.0" 89 | flutter_plus: 90 | dependency: "direct main" 91 | description: 92 | path: ".." 93 | relative: true 94 | source: path 95 | version: "1.0.1" 96 | flutter_test: 97 | dependency: "direct dev" 98 | description: flutter 99 | source: sdk 100 | version: "0.0.0" 101 | flutter_web_plugins: 102 | dependency: transitive 103 | description: flutter 104 | source: sdk 105 | version: "0.0.0" 106 | intl: 107 | dependency: transitive 108 | description: 109 | name: intl 110 | sha256: "910f85bce16fb5c6f614e117efa303e85a1731bb0081edf3604a2ae6e9a3cc91" 111 | url: "https://pub.dev" 112 | source: hosted 113 | version: "0.17.0" 114 | matcher: 115 | dependency: transitive 116 | description: 117 | name: matcher 118 | sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" 119 | url: "https://pub.dev" 120 | source: hosted 121 | version: "0.12.16" 122 | material_color_utilities: 123 | dependency: transitive 124 | description: 125 | name: material_color_utilities 126 | sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" 127 | url: "https://pub.dev" 128 | source: hosted 129 | version: "0.5.0" 130 | meta: 131 | dependency: transitive 132 | description: 133 | name: meta 134 | sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" 135 | url: "https://pub.dev" 136 | source: hosted 137 | version: "1.9.1" 138 | path: 139 | dependency: transitive 140 | description: 141 | name: path 142 | sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" 143 | url: "https://pub.dev" 144 | source: hosted 145 | version: "1.8.3" 146 | path_provider_linux: 147 | dependency: transitive 148 | description: 149 | name: path_provider_linux 150 | sha256: "938d2b6591587bcb009d2109a6ea464fd8fb2a75dc6423171b0d0afb1d27c708" 151 | url: "https://pub.dev" 152 | source: hosted 153 | version: "2.0.0" 154 | path_provider_platform_interface: 155 | dependency: transitive 156 | description: 157 | name: path_provider_platform_interface 158 | sha256: "2e14fc474b8acfc4111ac8eb0e37c2fe70234f9f8cd796f1560d03aa1689fa51" 159 | url: "https://pub.dev" 160 | source: hosted 161 | version: "2.0.0" 162 | path_provider_windows: 163 | dependency: transitive 164 | description: 165 | name: path_provider_windows 166 | sha256: ecd4d04c225596bcf0fbb86408a1f40084a02dfa412e60172ad52a7f12a781ef 167 | url: "https://pub.dev" 168 | source: hosted 169 | version: "2.0.0" 170 | platform: 171 | dependency: transitive 172 | description: 173 | name: platform 174 | sha256: ebc79f16b5f6b609aad4a5e63447d4795d16f7adee46e93ed03200848c006735 175 | url: "https://pub.dev" 176 | source: hosted 177 | version: "3.0.0" 178 | plugin_platform_interface: 179 | dependency: transitive 180 | description: 181 | name: plugin_platform_interface 182 | sha256: da3fdfeccc4d4ff2da8f8c556704c08f912542c5fb3cf2233ed75372384a034d 183 | url: "https://pub.dev" 184 | source: hosted 185 | version: "2.1.6" 186 | process: 187 | dependency: transitive 188 | description: 189 | name: process 190 | sha256: c7b9f7d8a6ee4407ab4f8a7d4a951f8f5659c40df14c0924e2e97c32372e9b14 191 | url: "https://pub.dev" 192 | source: hosted 193 | version: "4.1.0" 194 | shared_preferences: 195 | dependency: transitive 196 | description: 197 | name: shared_preferences 198 | sha256: "5c34bd1fd5ddfca85766659b1b82342d8b047ceb3ecf34f6dd439640a41ccff6" 199 | url: "https://pub.dev" 200 | source: hosted 201 | version: "2.0.6" 202 | shared_preferences_linux: 203 | dependency: transitive 204 | description: 205 | name: shared_preferences_linux 206 | sha256: "33fc7c6ced70d226645a9612132fbff9890805df4edd34f30840e7e738866fee" 207 | url: "https://pub.dev" 208 | source: hosted 209 | version: "2.0.0" 210 | shared_preferences_macos: 211 | dependency: transitive 212 | description: 213 | name: shared_preferences_macos 214 | sha256: "5d2bad07b196b6ad4cf21af6f7197a87264ef569199502b9352f76e5054f06ae" 215 | url: "https://pub.dev" 216 | source: hosted 217 | version: "2.0.0" 218 | shared_preferences_platform_interface: 219 | dependency: transitive 220 | description: 221 | name: shared_preferences_platform_interface 222 | sha256: "992f0fdc46d0a3c0ac2e5859f2de0e577bbe51f78a77ee8f357cbe626a2ad32d" 223 | url: "https://pub.dev" 224 | source: hosted 225 | version: "2.0.0" 226 | shared_preferences_web: 227 | dependency: transitive 228 | description: 229 | name: shared_preferences_web 230 | sha256: "09b72ec530a1b1f26cdbec6b138f980d97d4d86ebb86dbf6365369fbd4bb05c8" 231 | url: "https://pub.dev" 232 | source: hosted 233 | version: "2.0.0" 234 | shared_preferences_windows: 235 | dependency: transitive 236 | description: 237 | name: shared_preferences_windows 238 | sha256: "76c54a0148780d779a3fe332ece9ba8ad2c9dd0bc717ee7fce58bd06b5e8118f" 239 | url: "https://pub.dev" 240 | source: hosted 241 | version: "2.0.0" 242 | sky_engine: 243 | dependency: transitive 244 | description: flutter 245 | source: sdk 246 | version: "0.0.99" 247 | source_span: 248 | dependency: transitive 249 | description: 250 | name: source_span 251 | sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" 252 | url: "https://pub.dev" 253 | source: hosted 254 | version: "1.10.0" 255 | stack_trace: 256 | dependency: transitive 257 | description: 258 | name: stack_trace 259 | sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 260 | url: "https://pub.dev" 261 | source: hosted 262 | version: "1.11.0" 263 | stream_channel: 264 | dependency: transitive 265 | description: 266 | name: stream_channel 267 | sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" 268 | url: "https://pub.dev" 269 | source: hosted 270 | version: "2.1.1" 271 | string_scanner: 272 | dependency: transitive 273 | description: 274 | name: string_scanner 275 | sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" 276 | url: "https://pub.dev" 277 | source: hosted 278 | version: "1.2.0" 279 | term_glyph: 280 | dependency: transitive 281 | description: 282 | name: term_glyph 283 | sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 284 | url: "https://pub.dev" 285 | source: hosted 286 | version: "1.2.1" 287 | test_api: 288 | dependency: transitive 289 | description: 290 | name: test_api 291 | sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" 292 | url: "https://pub.dev" 293 | source: hosted 294 | version: "0.6.0" 295 | url_launcher: 296 | dependency: "direct main" 297 | description: 298 | name: url_launcher 299 | sha256: "704b2bd47392940d1ab71aa507b72f71989a255b2cb188cf3fff141b5921f364" 300 | url: "https://pub.dev" 301 | source: hosted 302 | version: "6.0.3" 303 | url_launcher_linux: 304 | dependency: transitive 305 | description: 306 | name: url_launcher_linux 307 | sha256: "86f3f393cde6bed2a05bfc7f05e52aeaf4f9911a3ad9ff78a42e89e57e5a264a" 308 | url: "https://pub.dev" 309 | source: hosted 310 | version: "2.0.0" 311 | url_launcher_macos: 312 | dependency: transitive 313 | description: 314 | name: url_launcher_macos 315 | sha256: f72b523da791d519aed53c12fd99c7dc50fdd1e4913da904081f3666d06334b5 316 | url: "https://pub.dev" 317 | source: hosted 318 | version: "2.0.0" 319 | url_launcher_platform_interface: 320 | dependency: transitive 321 | description: 322 | name: url_launcher_platform_interface 323 | sha256: be46294de4b963e3dc442dd207f82225bea5a802b9676b20d2ceca3f9dd3508f 324 | url: "https://pub.dev" 325 | source: hosted 326 | version: "2.0.1" 327 | url_launcher_web: 328 | dependency: transitive 329 | description: 330 | name: url_launcher_web 331 | sha256: "057e3458dfcc4276d171ae70cd98efc6d2485bf39b93a015349754e5dec0f657" 332 | url: "https://pub.dev" 333 | source: hosted 334 | version: "2.0.0" 335 | url_launcher_windows: 336 | dependency: transitive 337 | description: 338 | name: url_launcher_windows 339 | sha256: f98b970a12236957881fa28df0c6700f03d9dc5f471cf5ca6d205b77e7ad92d2 340 | url: "https://pub.dev" 341 | source: hosted 342 | version: "2.0.0" 343 | vector_math: 344 | dependency: transitive 345 | description: 346 | name: vector_math 347 | sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" 348 | url: "https://pub.dev" 349 | source: hosted 350 | version: "2.1.4" 351 | web: 352 | dependency: transitive 353 | description: 354 | name: web 355 | sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 356 | url: "https://pub.dev" 357 | source: hosted 358 | version: "0.1.4-beta" 359 | win32: 360 | dependency: transitive 361 | description: 362 | name: win32 363 | sha256: c6a3f4e4058b70b46e27b2935de2d1562c50680e7fb44833911d981db73826c2 364 | url: "https://pub.dev" 365 | source: hosted 366 | version: "2.0.0" 367 | xdg_directories: 368 | dependency: transitive 369 | description: 370 | name: xdg_directories 371 | sha256: "0186b3f2d66be9a12b0295bddcf8b6f8c0b0cc2f85c6287344e2a6366bc28457" 372 | url: "https://pub.dev" 373 | source: hosted 374 | version: "0.2.0" 375 | sdks: 376 | dart: ">=3.1.0-185.0.dev <4.0.0" 377 | flutter: ">=1.22.0" 378 | -------------------------------------------------------------------------------- /lib/src/widgets/src/container_plus.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import '../../../flutter_plus.dart'; 4 | import '../../../src/components/src/inner_shadow_render_plus.dart'; 5 | import '../../../src/components/src/skeleton_render_plus.dart'; 6 | 7 | class ContainerPlus extends StatefulWidget { 8 | /// ContainerPlus child widget 9 | final Widget? child; 10 | 11 | /// ContainerPlus padding 12 | final EdgeInsets padding; 13 | 14 | /// ContainerPlus margin 15 | final EdgeInsets? margin; 16 | 17 | /// ContainerPlus height 18 | final double? height; 19 | 20 | /// ContainerPlus width 21 | final double? width; 22 | 23 | /// ContainerPlus alignment 24 | final Alignment? alignment; 25 | 26 | /// ContainerPlus backgroundBlendMode 27 | final BlendMode? backgroundBlendMode; 28 | 29 | /// ContainerPlus boxConstraints 30 | final BoxConstraints? boxConstraints; 31 | 32 | /// ContainerPlus color when there is no gradient 33 | final Color? color; 34 | 35 | /// ContainerPlus image background 36 | final DecorationImage? image; 37 | 38 | /// ContainerPlus onTap action 39 | final Function()? onTap; 40 | 41 | /// ContainerPlus onTapDown action 42 | final Function(TapDownDetails)? onTapDown; 43 | 44 | /// ContainerPlus onTapUp action 45 | final Function(TapUpDetails)? onTapUp; 46 | 47 | /// ContainerPlus onTapCancel action 48 | final Function()? onTapCancel; 49 | 50 | /// ContainerPlus onDoubleTap action 51 | final Function()? onDoubleTap; 52 | 53 | /// ContainerPlus onLongPress action 54 | final Function()? onLongPress; 55 | 56 | /// ContainerPlus onPanUpdate action 57 | final Function(DragUpdateDetails)? onPanUpdate; 58 | 59 | /// ContainerPlus onPanEnd action 60 | final Function(DragStartDetails)? onPanStart; 61 | 62 | /// ContainerPlus onLongPress action 63 | final Function(DragEndDetails)? onPanEnd; 64 | 65 | /// ContainerPlus onPanDown action 66 | final Function(DragDownDetails)? onPanDown; 67 | 68 | /// ContainerPlus onPanCancel action 69 | final Function()? onPanCancel; 70 | 71 | /// ContainerPlus radius 72 | final RadiusPlus? radius; 73 | 74 | /// ContainerPlus border 75 | final BorderPlus? border; 76 | 77 | /// ContainerPlus shadows 78 | final List? shadows; 79 | 80 | /// ContainerPlus gradient 81 | final GradientPlus? gradient; 82 | 83 | /// ContainerPlus innerShadows 84 | final List? innerShadows; 85 | 86 | /// ContainerPlus skeleton 87 | final SkeletonPlus? skeleton; 88 | 89 | /// ContainerPlus inside Center widget 90 | final bool isCenter; 91 | 92 | /// ContainerPlus inside Expanded widget 93 | final bool isExpanded; 94 | 95 | /// ContainerPlus circle radius 96 | final bool isCircle; 97 | 98 | /// Async notify a parent the size and position of ContainerPlus 99 | final Function(Size?, Offset?)? notifyParent; 100 | 101 | ContainerPlus({ 102 | Key? key, 103 | this.height, 104 | this.width, 105 | this.color = Colors.transparent, 106 | this.child, 107 | this.padding = EdgeInsets.zero, 108 | this.margin = EdgeInsets.zero, 109 | this.image, 110 | this.alignment, 111 | this.backgroundBlendMode, 112 | this.boxConstraints, 113 | this.isCenter = false, 114 | this.isExpanded = false, 115 | this.isCircle = false, 116 | //functions 117 | this.onPanUpdate, 118 | this.onPanStart, 119 | this.onPanEnd, 120 | this.onPanDown, 121 | this.onPanCancel, 122 | this.onTap, 123 | this.onTapDown, 124 | this.onTapUp, 125 | this.onTapCancel, 126 | this.onDoubleTap, 127 | this.onLongPress, 128 | this.notifyParent, 129 | // Plus 130 | this.skeleton, 131 | this.radius, 132 | this.border, 133 | this.gradient, 134 | this.shadows, 135 | this.innerShadows, 136 | }) : super(key: key); 137 | 138 | @override 139 | _ContainerPlusState createState() => _ContainerPlusState(); 140 | } 141 | 142 | class _ContainerPlusState extends State { 143 | final _keyRect = GlobalKey(); 144 | Size? _containerSize; 145 | Offset? _containerPostion; 146 | 147 | @override 148 | void initState() { 149 | // close previus keyboard (add to navigatorObservers) 150 | WidgetsBinding.instance!.addPostFrameCallback((_) { 151 | // delay principalmente para casos por exemplo que o teclado está aberto 152 | Future.delayed(Duration(microseconds: 50), _afterLayout); 153 | }); 154 | super.initState(); 155 | } 156 | 157 | _afterLayout() { 158 | _getSizes(); 159 | _getPositions(); 160 | if (widget.notifyParent != null) { 161 | widget.notifyParent!( 162 | _containerSize, 163 | _containerPostion, 164 | ); 165 | } 166 | } 167 | 168 | @override 169 | Widget build(BuildContext context) { 170 | // var currentFocus = FocusScope.of(context); 171 | // if (!currentFocus.hasPrimaryFocus) { 172 | // currentFocus.unfocus(); 173 | // } 174 | 175 | var containerPlus = _buildContainerPlus(); 176 | 177 | if (widget.isCenter == true) { 178 | containerPlus = Center( 179 | child: containerPlus, 180 | ); 181 | } 182 | 183 | if (widget.isExpanded == true) { 184 | containerPlus = Expanded( 185 | child: containerPlus, 186 | ); 187 | } 188 | 189 | return containerPlus; 190 | } 191 | 192 | Widget _buildContainerPlus() { 193 | return Container( 194 | key: _keyRect, 195 | padding: EdgeInsets.zero, 196 | alignment: widget.alignment, 197 | constraints: widget.boxConstraints, 198 | margin: widget.margin, 199 | height: widget.height, 200 | width: widget.width, 201 | decoration: _buildOutDecoration(), 202 | child: ClipRRect( 203 | borderRadius: _buildRadius(), 204 | child: _buildInnerShadow( 205 | Padding( 206 | padding: 207 | skeletonEnabled == true ? EdgeInsets.all(0) : widget.padding, 208 | child: skeletonEnabled == true ? _buildSkeleton() : _buildChild(), 209 | ), 210 | ), 211 | ), 212 | ); 213 | } 214 | 215 | Widget? _buildSkeleton() { 216 | // to calculate height 217 | 218 | if (skeletonEnabled == false) { 219 | return widget.child; 220 | } else { 221 | return Container( 222 | height: _containerSize?.height ?? 0, 223 | width: _containerSize?.width ?? 0, 224 | child: SkeletonRenderPlus( 225 | skeletonPlus: widget.skeleton, 226 | ), 227 | ); 228 | } 229 | } 230 | 231 | Widget _buildInnerShadow(Widget child) { 232 | if (widget.innerShadows == null || widget.innerShadows!.isEmpty) { 233 | return child; 234 | } else { 235 | return InnerShadowRenderPlus( 236 | shadows: widget.innerShadows == null 237 | ? [] 238 | : widget.innerShadows! 239 | .map( 240 | (innerShadow) => Shadow( 241 | color: innerShadow.color, 242 | blurRadius: innerShadow.blur, 243 | offset: Offset( 244 | innerShadow.moveRight, 245 | innerShadow.moveDown, 246 | ), 247 | ), 248 | ) 249 | .toList(), 250 | child: Container( 251 | decoration: _buildInDecoration(), 252 | child: child, 253 | ), 254 | ); 255 | } 256 | } 257 | 258 | Widget? _buildChild() { 259 | if (hasGestureDetector == true) { 260 | return _buildGestureDetector(); 261 | } else { 262 | return widget.child; 263 | } 264 | } 265 | 266 | Widget _buildGestureDetector() { 267 | return GestureDetector( 268 | // tap 269 | onTap: widget.onTap ?? null, 270 | onDoubleTap: widget.onDoubleTap ?? null, 271 | onLongPress: widget.onLongPress ?? null, 272 | onTapDown: widget.onTapDown ?? null, 273 | onTapUp: widget.onTapUp ?? null, 274 | onTapCancel: widget.onTapCancel ?? null, 275 | // pan 276 | onPanCancel: widget.onPanCancel ?? null, 277 | onPanDown: widget.onPanDown ?? null, 278 | onPanEnd: widget.onPanEnd ?? null, 279 | // onPanEnd: (details) { 280 | // print('xxx'); 281 | // }, 282 | onPanStart: widget.onPanStart ?? null, 283 | onPanUpdate: widget.onPanUpdate ?? null, 284 | // others 285 | child: widget.child, 286 | behavior: HitTestBehavior.translucent, 287 | ); 288 | } 289 | 290 | bool get hasGestureDetector { 291 | if (widget.onTap != null || 292 | widget.onDoubleTap != null || 293 | widget.onLongPress != null || 294 | widget.onTapDown != null || 295 | widget.onTapUp != null || 296 | widget.onTapCancel != null || 297 | widget.onPanCancel != null || 298 | widget.onPanDown != null || 299 | widget.onPanEnd != null || 300 | widget.onPanStart != null || 301 | widget.onPanUpdate != null) { 302 | return true; 303 | } else { 304 | return false; 305 | } 306 | } 307 | 308 | BoxDecoration _buildInDecoration() { 309 | return BoxDecoration( 310 | color: _containerColor(), 311 | // shape: widget.isCircle ? BoxShape.circle : BoxShape.rectangle, 312 | shape: BoxShape.rectangle, 313 | border: _buildBorder(), 314 | borderRadius: _buildRadius(), 315 | boxShadow: _buildShadow(), 316 | gradient: _buildGradient(), 317 | image: _buildDecorationImage(), 318 | backgroundBlendMode: widget.backgroundBlendMode, 319 | ); 320 | } 321 | 322 | BoxDecoration _buildOutDecoration() { 323 | return BoxDecoration( 324 | color: _containerColor(), 325 | // shape: widget.isCircle ? BoxShape.circle : BoxShape.rectangle, 326 | shape: BoxShape.rectangle, 327 | border: _buildBorder(), 328 | borderRadius: _buildRadius(), 329 | boxShadow: _buildShadow(), 330 | gradient: _buildGradient(), 331 | image: _buildDecorationImage(), 332 | backgroundBlendMode: widget.backgroundBlendMode, 333 | ); 334 | } 335 | 336 | Color? _containerColor() { 337 | if (widget.gradient != null) { 338 | return Colors.red; 339 | } else { 340 | return skeletonEnabled == true ? Colors.transparent : widget.color; 341 | } 342 | } 343 | 344 | List _buildShadow() { 345 | if (widget.shadows == null || skeletonShowShadow == false) return []; 346 | return widget.shadows!.map((shadow) { 347 | return BoxShadow( 348 | color: shadow.opacity != null 349 | ? shadow.color.withOpacity(shadow.opacity!) 350 | : shadow.color, 351 | blurRadius: shadow.blur, 352 | spreadRadius: shadow.spread, 353 | offset: Offset( 354 | shadow.moveRight, 355 | shadow.moveDown, 356 | ), 357 | ); 358 | }).toList(); 359 | } 360 | 361 | DecorationImage? _buildDecorationImage() { 362 | return widget.image; 363 | } 364 | 365 | Gradient? _buildGradient() { 366 | if (widget.gradient != null) { 367 | return widget.gradient!.toGradient; 368 | } else { 369 | return null; 370 | } 371 | } 372 | 373 | Border _buildBorder() { 374 | if (widget.border == null || skeletonShowBorder == false) { 375 | return Border.all( 376 | color: Colors.transparent, 377 | width: 0, 378 | style: BorderStyle.none, 379 | ); 380 | } else { 381 | return widget.border!.toBorder; 382 | } 383 | } 384 | 385 | BorderRadius _buildRadius() { 386 | if (widget.isCircle == true && _containerSize != null) { 387 | return BorderRadius.all( 388 | Radius.circular(_containerSize!.height / 2), 389 | ); 390 | } else if (widget.radius == null) { 391 | return BorderRadius.zero; 392 | } else { 393 | return widget.radius!.toBorderRadius; 394 | } 395 | } 396 | 397 | _getSizes() { 398 | final renderBox = _keyRect.currentContext?.findRenderObject() as RenderBox?; 399 | if (renderBox != null) { 400 | final size = renderBox.size; 401 | setState(() { 402 | _containerSize = size; 403 | }); 404 | // print("SIZE: $size"); 405 | } else { 406 | // print('_getSizes renderBox NULL'); 407 | } 408 | } 409 | 410 | _getPositions() { 411 | final renderBox = _keyRect.currentContext?.findRenderObject() as RenderBox?; 412 | if (renderBox != null) { 413 | final position = renderBox.localToGlobal(Offset.zero); 414 | setState(() { 415 | _containerPostion = position; 416 | }); 417 | // print("POSITION: $position "); 418 | } else { 419 | // print('_getPositions renderBox NULL'); 420 | } 421 | } 422 | 423 | bool get skeletonEnabled { 424 | if (widget.skeleton != null && 425 | widget.skeleton!.enabled == true && 426 | _containerSize != null) { 427 | return true; 428 | } else { 429 | return false; 430 | } 431 | } 432 | 433 | bool get skeletonShowShadow { 434 | if (skeletonEnabled == false || widget.skeleton?.showShadows == true) { 435 | return true; 436 | } else { 437 | return false; 438 | } 439 | } 440 | 441 | bool get skeletonShowBorder { 442 | if (skeletonEnabled == false || widget.skeleton?.showBorders == true) { 443 | return true; 444 | } else { 445 | return false; 446 | } 447 | } 448 | } 449 | -------------------------------------------------------------------------------- /lib/src/widgets/src/text_field_plus.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:flutter/cupertino.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:flutter/services.dart'; 6 | import 'package:intl/intl.dart'; 7 | 8 | import '../../../flutter_plus.dart'; 9 | import '../../../src/components/src/text_field_mask_plus.dart'; 10 | 11 | class TextFieldPlus extends StatelessWidget { 12 | /// TextFieldPlus padding 13 | final EdgeInsets? padding; 14 | 15 | /// TextFieldPlus margin 16 | final EdgeInsets? margin; 17 | 18 | /// TextFieldPlus height 19 | final double height; 20 | 21 | /// TextFieldPlus width 22 | final double? width; 23 | 24 | /// TextFieldPlus alignment 25 | final Alignment? alignment; 26 | 27 | /// TextFieldPlus backgroundColor 28 | final Color? backgroundColor; 29 | 30 | /// TextFieldPlus controller 31 | final TextEditingController? controller; 32 | 33 | /// TextFieldPlus focusNode 34 | final FocusNode? focusNode; 35 | 36 | /// TextFieldPlus textInputType 37 | final TextInputType? textInputType; 38 | 39 | /// TextFieldPlus textCapitalization 40 | final TextCapitalization textCapitalization; 41 | 42 | /// TextFieldPlus textAlign 43 | final TextAlign textAlign; 44 | 45 | /// TextFieldPlus textAlignVertical 46 | final TextAlignVertical textAlignVertical; 47 | 48 | /// TextFieldPlus onChanged action 49 | final Function(String)? onChanged; 50 | 51 | /// TextFieldPlus onTap action 52 | final Function()? onTap; 53 | 54 | /// TextFieldPlus onEditingComplete action 55 | final Function()? onEditingComplete; 56 | 57 | /// TextFieldPlus onSubmitted action 58 | final Function(String)? onSubmitted; 59 | 60 | /// TextFieldPlus mask -> (+##) #####-##### 61 | final String? mask; 62 | 63 | /// TextFieldPlus placeholder [TextPlus] 64 | final TextPlus? placeholder; 65 | 66 | /// TextFieldPlus textInputAction 67 | final TextInputAction textInputAction; 68 | 69 | /// TextFieldPlus maxLength 70 | final int? maxLength; 71 | 72 | /// TextFieldPlus maxLines 73 | final int? maxLines; 74 | 75 | /// TextFieldPlus cursorColor 76 | final Color? cursorColor; 77 | 78 | /// TextFieldPlus cursorRadius 79 | final double cursorRadius; 80 | 81 | /// TextFieldPlus cursorWidth 82 | final double cursorWidth; 83 | 84 | /// TextFieldPlus showCursor -> true or false 85 | final bool showCursor; 86 | 87 | /// TextFieldPlus enabled -> true or false 88 | final bool? enabled; 89 | 90 | /// TextFieldPlus autocorrect -> true or false 91 | final bool autocorrect; 92 | 93 | /// TextFieldPlus autofocus -> true or false 94 | final bool autofocus; 95 | 96 | /// TextFieldPlus obscureText -> true or false 97 | final bool obscureText; 98 | 99 | /// TextFieldPlus readOnly -> true or false 100 | final bool readOnly; 101 | 102 | /// TextFieldPlus onlyNumbers -> true or false 103 | final bool onlyNumbers; 104 | 105 | /// TextFieldPlus textColor 106 | final Color? textColor; 107 | 108 | /// TextFieldPlus fontSize 109 | final double? fontSize; 110 | 111 | /// TextFieldPlus fontWeight 112 | final FontWeight? fontWeight; 113 | 114 | /// TextFieldPlus fontStyle 115 | final FontStyle? fontStyle; 116 | 117 | /// TextFieldPlus letterSpacing 118 | final double? letterSpacing; 119 | 120 | /// TextFieldPlus wordSpacing 121 | final double? wordSpacing; 122 | 123 | /// TextFieldPlus fontFamily 124 | final String? fontFamily; 125 | 126 | /// TextFieldPlus prefixWidget 127 | final Widget? prefixWidget; 128 | 129 | /// TextFieldPlus suffixWidget 130 | final Widget? suffixWidget; 131 | 132 | /// TextFieldPlus textDecorationPlus 133 | final TextDecorationPlus? textDecorationPlus; 134 | 135 | /// TextFieldPlus radius 136 | final RadiusPlus? radius; 137 | 138 | /// TextFieldPlus border 139 | final BorderPlus? border; 140 | 141 | /// TextFieldPlus shadows 142 | final List? shadows; 143 | 144 | /// TextFieldPlus gradient 145 | final GradientPlus? gradient; 146 | 147 | /// ButtonPlus skeleton 148 | final SkeletonPlus? skeleton; 149 | 150 | /// TextFieldPlus inside Center widget 151 | final bool isCenter; 152 | 153 | /// TextFieldPlus inside Expanded widget 154 | final bool isExpanded; 155 | 156 | final List? inpuFormatters; 157 | 158 | TextFieldPlus({ 159 | this.enabled, 160 | this.isCenter = false, 161 | this.isExpanded = false, 162 | this.padding, 163 | this.margin, 164 | this.height = 50, 165 | this.width, 166 | this.radius, 167 | this.border, 168 | this.shadows, 169 | this.gradient, 170 | this.skeleton, 171 | this.alignment, 172 | this.backgroundColor, 173 | this.controller, 174 | this.textInputType, 175 | this.textCapitalization = TextCapitalization.none, 176 | this.textAlign = TextAlign.start, 177 | this.mask, 178 | this.maxLength, 179 | this.maxLines, 180 | this.autocorrect = false, 181 | this.autofocus = false, 182 | this.obscureText = false, 183 | this.onlyNumbers = false, 184 | this.focusNode, 185 | this.onChanged, 186 | this.readOnly = false, 187 | this.cursorColor, 188 | this.textAlignVertical = TextAlignVertical.center, 189 | this.textColor, 190 | this.fontSize, 191 | this.fontWeight, 192 | this.fontStyle, 193 | this.letterSpacing, 194 | this.wordSpacing, 195 | this.fontFamily, 196 | this.textDecorationPlus, 197 | this.placeholder, 198 | this.cursorRadius = 2, 199 | this.cursorWidth = 2, 200 | this.showCursor = true, 201 | this.prefixWidget, 202 | this.suffixWidget, 203 | this.onTap, 204 | this.onEditingComplete, 205 | this.onSubmitted, 206 | this.textInputAction = TextInputAction.done, 207 | this.inpuFormatters, 208 | }); 209 | 210 | static ContainerPlus? _containerPlus; 211 | 212 | @override 213 | Widget build(BuildContext context) { 214 | return _buildContainerPlus()!; 215 | } 216 | 217 | ContainerPlus? _buildContainerPlus() { 218 | _containerPlus = ContainerPlus( 219 | padding: padding ?? EdgeInsets.symmetric(horizontal: 4), 220 | margin: margin, 221 | isCenter: isCenter, 222 | isExpanded: isExpanded, 223 | alignment: alignment, 224 | color: backgroundColor, 225 | height: height, 226 | width: width, 227 | skeleton: skeleton, 228 | border: border, 229 | gradient: gradient, 230 | radius: radius, 231 | shadows: shadows, 232 | // notifyParent: () => setState(() {}), 233 | child: _buildTextField(), 234 | ); 235 | return _containerPlus; 236 | } 237 | 238 | Widget _buildTextField() { 239 | return CupertinoTextField( 240 | padding: padding ?? EdgeInsets.symmetric(horizontal: 4), 241 | autocorrect: autocorrect, 242 | enabled: enabled ?? true, 243 | controller: controller, 244 | focusNode: focusNode, 245 | autofocus: autofocus, 246 | textCapitalization: textCapitalization, 247 | keyboardAppearance: Brightness.dark, 248 | cursorColor: cursorColor, 249 | textAlign: TextAlign.start, 250 | obscureText: obscureText, 251 | readOnly: readOnly, 252 | textAlignVertical: textAlignVertical, 253 | keyboardType: onlyNumbers == true && textInputType == null 254 | ? TextInputType.number 255 | : textInputType, 256 | maxLines: maxLines, 257 | maxLength: maxLength, 258 | // maxLengthEnforced: true, 259 | maxLengthEnforcement: MaxLengthEnforcement.none, 260 | showCursor: showCursor, 261 | cursorRadius: Radius.circular(cursorRadius), 262 | cursorWidth: cursorWidth, 263 | placeholder: placeholder?.text, 264 | placeholderStyle: _buildPlaceholderTextStyle(), 265 | style: _buildTextStyle(), 266 | inputFormatters: _getFormatters(), 267 | prefix: prefixWidget, 268 | suffix: suffixWidget, 269 | onChanged: onChanged, 270 | onTap: onTap, 271 | onEditingComplete: onEditingComplete, 272 | onSubmitted: onSubmitted, 273 | textInputAction: textInputAction, 274 | // remove native decoration 275 | decoration: null, 276 | ); 277 | } 278 | 279 | TextStyle _buildTextStyle() { 280 | return TextStyle( 281 | backgroundColor: Colors.transparent, 282 | color: textColor, 283 | fontSize: fontSize, 284 | fontWeight: fontWeight, 285 | fontStyle: fontStyle, 286 | decoration: textDecorationPlus?.textDecoration, 287 | decorationColor: textDecorationPlus?.color, 288 | decorationStyle: textDecorationPlus?.decorationStyle, 289 | decorationThickness: textDecorationPlus?.decorationThickness, 290 | letterSpacing: letterSpacing, 291 | fontFamily: fontFamily, 292 | wordSpacing: wordSpacing, 293 | ); 294 | } 295 | 296 | TextStyle? _buildPlaceholderTextStyle() { 297 | if (placeholder == null) return null; 298 | return TextStyle( 299 | backgroundColor: placeholder!.backgroundColor, 300 | color: placeholder!.color, 301 | fontSize: placeholder!.fontSize, 302 | fontWeight: placeholder!.fontWeight, 303 | fontStyle: placeholder!.fontStyle, 304 | decoration: placeholder!.textDecorationPlus?.textDecoration, 305 | decorationColor: placeholder!.textDecorationPlus?.color, 306 | decorationStyle: placeholder!.textDecorationPlus?.decorationStyle, 307 | decorationThickness: placeholder!.textDecorationPlus?.decorationThickness, 308 | letterSpacing: placeholder!.letterSpacing, 309 | fontFamily: placeholder!.fontFamily, 310 | wordSpacing: placeholder!.wordSpacing, 311 | height: placeholder!.height, 312 | ); 313 | } 314 | 315 | List _getFormatters() { 316 | var textInputFormatters = []; 317 | 318 | if (inpuFormatters != null && inpuFormatters!.isNotEmpty) { 319 | textInputFormatters.addAll(inpuFormatters!); 320 | } 321 | 322 | if (maxLength != null) { 323 | // var maxLengthFormatter = LengthLimitingTextInputFormatter(maxLength); 324 | // textInputFormatters.add(wmaxLengthFormatter); 325 | textInputFormatters.add(MaxLengthTextInputFormatter(maxLength)); 326 | } 327 | 328 | if (mask != null) { 329 | var maskFormatter = 330 | TextFieldMaskPlus(mask: mask!, filter: {"#": RegExp(r'[0-9]')}); 331 | textInputFormatters.add(maskFormatter); 332 | } 333 | 334 | if (onlyNumbers == true) { 335 | // textInputFormatters.add(WhitelistingTextInputFormatter.digitsOnly); 336 | textInputFormatters.add(FilteringTextInputFormatter.digitsOnly); 337 | // textInputFormatters.add(DecimalTextInputFormatter()); 338 | } 339 | 340 | return textInputFormatters.map((e) => e as TextInputFormatter).toList(); 341 | } 342 | } 343 | 344 | class MaxLengthTextInputFormatter extends TextInputFormatter { 345 | final int? maxLength; 346 | 347 | MaxLengthTextInputFormatter(this.maxLength); 348 | 349 | @override 350 | TextEditingValue formatEditUpdate( 351 | TextEditingValue oldValue, TextEditingValue newValue) { 352 | if (newValue.text.length > maxLength!) { 353 | return oldValue; 354 | } else { 355 | return newValue; 356 | } 357 | } 358 | } 359 | 360 | class CurrencyTextInputFormatter extends TextInputFormatter { 361 | CurrencyTextInputFormatter({ 362 | this.locale, 363 | this.name, 364 | this.symbol, 365 | this.decimalDigits, 366 | this.customPattern, 367 | this.turnOffGrouping = false, 368 | }); 369 | 370 | final String? locale; 371 | final String? name; 372 | final String? symbol; 373 | final int? decimalDigits; 374 | final String? customPattern; 375 | final bool turnOffGrouping; 376 | 377 | num _newNum = 0; 378 | String _newString = ''; 379 | 380 | void _formatter(String newText, bool isNegative) { 381 | final format = NumberFormat.currency( 382 | locale: locale, 383 | name: name, 384 | symbol: symbol, 385 | decimalDigits: decimalDigits, 386 | customPattern: customPattern, 387 | ); 388 | if (turnOffGrouping) { 389 | format.turnOffGrouping(); 390 | } 391 | 392 | _newNum = num.parse(newText); 393 | if (format.decimalDigits! > 0) { 394 | _newNum /= pow(10, format.decimalDigits!); 395 | } 396 | _newString = (isNegative ? '-' : '') + format.format(_newNum).trim(); 397 | } 398 | 399 | @override 400 | TextEditingValue formatEditUpdate( 401 | TextEditingValue oldValue, 402 | TextEditingValue newValue, 403 | ) { 404 | final isInsertedCharacter = 405 | oldValue.text.length + 1 == newValue.text.length && 406 | newValue.text.startsWith(oldValue.text); 407 | final isRemovedCharacter = 408 | oldValue.text.length - 1 == newValue.text.length && 409 | oldValue.text.startsWith(newValue.text); 410 | 411 | if (!isInsertedCharacter && !isRemovedCharacter) { 412 | return oldValue; 413 | } 414 | 415 | final isNegative = newValue.text.startsWith('-'); 416 | var newText = newValue.text.replaceAll(RegExp('[^0-9]'), ''); 417 | 418 | // If the user wants to remove a digit, but the last character of the 419 | // formatted text is not a digit (for example, "1,00 €"), we need to remove 420 | // the digit manually. 421 | if (isRemovedCharacter && !_lastCharacterIsDigit(oldValue.text)) { 422 | final length = newText.length - 1; 423 | newText = newText.substring(0, length > 0 ? length : 0); 424 | } 425 | 426 | _formatter(newText, isNegative); 427 | 428 | if (newText.trim() == '') { 429 | return newValue.copyWith( 430 | text: isNegative ? '-' : '', 431 | selection: TextSelection.collapsed(offset: isNegative ? 1 : 0), 432 | ); 433 | } else if (newText == '00' || newText == '000') { 434 | return TextEditingValue( 435 | text: isNegative ? '-' : '', 436 | selection: TextSelection.collapsed(offset: isNegative ? 1 : 0), 437 | ); 438 | } 439 | 440 | return TextEditingValue( 441 | text: _newString, 442 | selection: TextSelection.collapsed(offset: _newString.length), 443 | ); 444 | } 445 | 446 | static bool _lastCharacterIsDigit(String text) { 447 | final lastChar = text.substring(text.length - 1); 448 | return RegExp('[0-9]').hasMatch(lastChar); 449 | } 450 | 451 | /// Get String type value with format such as `$ 2,000.00` 452 | String getFormattedValue() { 453 | return _newString; 454 | } 455 | 456 | /// Get num type value without format such as `2000.00` 457 | num getUnformattedValue() { 458 | return _newNum; 459 | } 460 | 461 | /// Method for formatting value. 462 | /// You can use initialValue with this method. 463 | String format(String value) { 464 | final isNegative = value.startsWith('-'); 465 | final newText = value.replaceAll(RegExp('[^0-9]'), ''); 466 | _formatter(newText, isNegative); 467 | return _newString; 468 | } 469 | } 470 | --------------------------------------------------------------------------------