├── lib ├── src │ ├── model │ │ ├── status.dart │ │ ├── colors.dart │ │ └── params.dart │ ├── theme │ │ ├── themings │ │ │ ├── icon_style.dart │ │ │ ├── animation_style.dart │ │ │ ├── support_style.dart │ │ │ └── text_style.dart │ │ └── utils.dart │ ├── components │ │ ├── internal │ │ │ ├── clippers │ │ │ │ ├── inverted_cliprrect.dart │ │ │ │ ├── vertical_rectangle_clipper.dart │ │ │ │ └── double_cliprrect.dart │ │ │ ├── scroll_behavior.dart │ │ │ ├── no_splash_factory.dart │ │ │ └── transparent_page_route.dart │ │ ├── divider │ │ │ └── divider.dart │ │ ├── tabs │ │ │ ├── tab_style.dart │ │ │ └── tabs.dart │ │ ├── card │ │ │ ├── card_status_apperance.dart │ │ │ └── card_style.dart │ │ ├── spinner │ │ │ ├── spinner_style.dart │ │ │ ├── spinner_painter.dart │ │ │ └── spinner.dart │ │ ├── app_bar │ │ │ └── app_bar_style.dart │ │ ├── icon │ │ │ └── icon.dart │ │ ├── select │ │ │ ├── select_item.dart │ │ │ └── select_overlay.dart │ │ ├── global │ │ │ ├── theme.dart │ │ │ ├── outlined_gesture_detector.dart │ │ │ ├── layout.dart │ │ │ └── app │ │ │ │ ├── equinox_toast_service.dart │ │ │ │ └── equinox_dialog_service.dart │ │ ├── toast │ │ │ ├── toast_data.dart │ │ │ ├── toast_style.dart │ │ │ └── toast_reveal.dart │ │ ├── text │ │ │ └── text_params.dart │ │ ├── tab_bar │ │ │ └── tab_bar.dart │ │ ├── list_item │ │ │ ├── list_item_style.dart │ │ │ └── list_item.dart │ │ ├── progress_bar │ │ │ └── progress_bar_style.dart │ │ ├── toggle │ │ │ └── toggle_style.dart │ │ ├── radio │ │ │ └── radio_style.dart │ │ ├── checkbox │ │ │ └── checkbox_style.dart │ │ ├── dialog │ │ │ └── dialog.dart │ │ └── icon_button │ │ │ └── icon_button.dart │ ├── equinox_internal.dart │ └── utils.dart └── equinox.dart ├── equinox_visualqa ├── desktop │ ├── .gitignore │ ├── assets │ │ └── icon.png │ ├── cmd │ │ ├── options.go │ │ └── main.go │ ├── go.mod │ └── go.sum ├── 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 │ │ │ │ │ ├── values │ │ │ │ │ │ └── styles.xml │ │ │ │ │ └── drawable │ │ │ │ │ │ └── launch_background.xml │ │ │ │ ├── java │ │ │ │ │ └── com │ │ │ │ │ │ └── example │ │ │ │ │ │ └── equinox_visualqa │ │ │ │ │ │ └── MainActivity.java │ │ │ │ └── AndroidManifest.xml │ │ │ ├── debug │ │ │ │ └── AndroidManifest.xml │ │ │ └── profile │ │ │ │ └── AndroidManifest.xml │ │ └── build.gradle │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ ├── settings.gradle │ └── build.gradle ├── ios │ ├── Flutter │ │ ├── Debug.xcconfig │ │ ├── Release.xcconfig │ │ └── AppFrameworkInfo.plist │ ├── Runner │ │ ├── AppDelegate.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 │ │ ├── main.m │ │ ├── AppDelegate.m │ │ ├── Info.plist │ │ └── Base.lproj │ │ │ ├── Main.storyboard │ │ │ └── LaunchScreen.storyboard │ ├── Runner.xcworkspace │ │ └── contents.xcworkspacedata │ └── Runner.xcodeproj │ │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── .metadata ├── lib │ ├── utils.dart │ ├── state.dart │ ├── main_desktop.dart │ ├── components │ │ ├── spinner.dart │ │ ├── card.dart │ │ ├── toggle.dart │ │ ├── tabs.dart │ │ ├── radio.dart │ │ └── toast.dart │ ├── management │ │ ├── showcase_state.dart │ │ └── interactive_playground.dart │ └── theme.dart ├── README.md ├── test │ └── widget_test.dart ├── .gitignore └── pubspec.yaml ├── test └── widget_test.dart ├── example ├── 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 │ │ │ │ │ ├── values │ │ │ │ │ │ └── styles.xml │ │ │ │ │ └── drawable │ │ │ │ │ │ └── launch_background.xml │ │ │ │ ├── java │ │ │ │ │ └── com │ │ │ │ │ │ └── example │ │ │ │ │ │ └── example │ │ │ │ │ │ └── MainActivity.java │ │ │ │ └── AndroidManifest.xml │ │ │ ├── debug │ │ │ │ └── AndroidManifest.xml │ │ │ └── profile │ │ │ │ └── AndroidManifest.xml │ │ └── build.gradle │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ ├── settings.gradle │ └── build.gradle ├── ios │ ├── Flutter │ │ ├── Debug.xcconfig │ │ ├── Release.xcconfig │ │ └── AppFrameworkInfo.plist │ ├── Runner │ │ ├── AppDelegate.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 │ │ ├── main.m │ │ ├── AppDelegate.m │ │ ├── Info.plist │ │ └── Base.lproj │ │ │ ├── Main.storyboard │ │ │ └── LaunchScreen.storyboard │ ├── Runner.xcworkspace │ │ └── contents.xcworkspacedata │ └── Runner.xcodeproj │ │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── .metadata ├── lib │ ├── main.dart │ └── home_page.dart ├── README.md ├── .gitignore └── pubspec.yaml ├── .github └── ISSUE_TEMPLATE │ ├── custom.md │ ├── feature_request.md │ └── bug_report.md ├── .metadata ├── LICENSE ├── .gitignore ├── CHANGELOG.md ├── README.md ├── pubspec.yaml ├── CODE_OF_CONDUCT.md └── pubspec.lock /lib/src/model/status.dart: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /equinox_visualqa/desktop/.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | -------------------------------------------------------------------------------- /test/widget_test.dart: -------------------------------------------------------------------------------- 1 | void main() { 2 | 3 | } -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | -------------------------------------------------------------------------------- /example/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /example/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /equinox_visualqa/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | -------------------------------------------------------------------------------- /equinox_visualqa/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /equinox_visualqa/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /equinox_visualqa/desktop/assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kekland/equinox/HEAD/equinox_visualqa/desktop/assets/icon.png -------------------------------------------------------------------------------- /example/ios/Runner/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface AppDelegate : FlutterAppDelegate 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /equinox_visualqa/ios/Runner/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface AppDelegate : FlutterAppDelegate 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kekland/equinox/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/kekland/equinox/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/kekland/equinox/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/kekland/equinox/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/kekland/equinox/HEAD/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /equinox_visualqa/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kekland/equinox/HEAD/equinox_visualqa/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /equinox_visualqa/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kekland/equinox/HEAD/equinox_visualqa/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /equinox_visualqa/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kekland/equinox/HEAD/equinox_visualqa/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /equinox_visualqa/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kekland/equinox/HEAD/equinox_visualqa/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kekland/equinox/HEAD/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /equinox_visualqa/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kekland/equinox/HEAD/equinox_visualqa/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kekland/equinox/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/kekland/equinox/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/kekland/equinox/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/kekland/equinox/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/kekland/equinox/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/kekland/equinox/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/kekland/equinox/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/kekland/equinox/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/kekland/equinox/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/kekland/equinox/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/kekland/equinox/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/kekland/equinox/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/kekland/equinox/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/kekland/equinox/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/kekland/equinox/HEAD/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/custom.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Custom issue template 3 | about: Describe this issue template's purpose here. 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | -------------------------------------------------------------------------------- /equinox_visualqa/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kekland/equinox/HEAD/equinox_visualqa/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kekland/equinox/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/kekland/equinox/HEAD/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /equinox_visualqa/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kekland/equinox/HEAD/equinox_visualqa/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /equinox_visualqa/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kekland/equinox/HEAD/equinox_visualqa/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /equinox_visualqa/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kekland/equinox/HEAD/equinox_visualqa/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /equinox_visualqa/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kekland/equinox/HEAD/equinox_visualqa/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /equinox_visualqa/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kekland/equinox/HEAD/equinox_visualqa/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /equinox_visualqa/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kekland/equinox/HEAD/equinox_visualqa/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /equinox_visualqa/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kekland/equinox/HEAD/equinox_visualqa/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /equinox_visualqa/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kekland/equinox/HEAD/equinox_visualqa/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /equinox_visualqa/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kekland/equinox/HEAD/equinox_visualqa/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /equinox_visualqa/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kekland/equinox/HEAD/equinox_visualqa/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /equinox_visualqa/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kekland/equinox/HEAD/equinox_visualqa/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /equinox_visualqa/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kekland/equinox/HEAD/equinox_visualqa/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /equinox_visualqa/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kekland/equinox/HEAD/equinox_visualqa/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /equinox_visualqa/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kekland/equinox/HEAD/equinox_visualqa/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /equinox_visualqa/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kekland/equinox/HEAD/equinox_visualqa/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /equinox_visualqa/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kekland/equinox/HEAD/equinox_visualqa/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /equinox_visualqa/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kekland/equinox/HEAD/equinox_visualqa/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /equinox_visualqa/desktop/cmd/options.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/go-flutter-desktop/go-flutter" 5 | ) 6 | 7 | var options = []flutter.Option{ 8 | flutter.WindowInitialDimensions(800, 1280), 9 | } 10 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /equinox_visualqa/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /equinox_visualqa/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /lib/src/model/colors.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | 3 | class Colors { 4 | static const Color black = Color(0xFF000000); 5 | static const Color transparent = Color(0x00000000); 6 | static const Color white = Color(0xFFFFFFFF); 7 | } 8 | -------------------------------------------------------------------------------- /equinox_visualqa/desktop/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/kekland/equinox/desktop 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/go-flutter-desktop/go-flutter v0.26.0 7 | github.com/pkg/errors v0.8.1 8 | github.com/stretchr/objx v0.2.0 // indirect 9 | ) 10 | -------------------------------------------------------------------------------- /example/ios/Runner/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import "AppDelegate.h" 4 | 5 | int main(int argc, char* argv[]) { 6 | @autoreleasepool { 7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /lib/src/theme/themings/icon_style.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | 3 | final StyleData iconStyle = StyleData({ 4 | 'icon-size': 24.0, 5 | 'icon-color': 'text-basic-color', 6 | 'icon-active-color': 'text-hint-color', 7 | 'icon-disabled-color': 'text-disabled-color', 8 | }); 9 | -------------------------------------------------------------------------------- /equinox_visualqa/ios/Runner/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import "AppDelegate.h" 4 | 5 | int main(int argc, char* argv[]) { 6 | @autoreleasepool { 7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /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-4.10.2-all.zip 7 | -------------------------------------------------------------------------------- /equinox_visualqa/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-4.10.2-all.zip 7 | -------------------------------------------------------------------------------- /.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: 362b999b90d53859aa7b926a59c970f3ea31abf4 8 | channel: dev 9 | 10 | project_type: app 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: 7a4c33425ddd78c54aba07d86f3f9a4a0051769b 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /equinox_visualqa/.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: 7a4c33425ddd78c54aba07d86f3f9a4a0051769b 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 | -------------------------------------------------------------------------------- /lib/src/theme/utils.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | 3 | String generateSelector(List items) { 4 | List nonNull = items.where((i) => i != null).toList(); 5 | String string = ""; 6 | 7 | for (final item in nonNull) { 8 | string += enumValueToString(item); 9 | string += "-"; 10 | } 11 | 12 | return string.substring(0, string.length - 1); 13 | } 14 | -------------------------------------------------------------------------------- /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. -------------------------------------------------------------------------------- /equinox_visualqa/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /equinox_visualqa/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /equinox_visualqa/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. -------------------------------------------------------------------------------- /lib/src/theme/themings/animation_style.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | final StyleData animationStyle = StyleData({ 5 | 'minor-animation-duration': Duration(milliseconds: 150), 6 | 'minor-animation-curve': Curves.easeInOut, 7 | 'major-animation-duration': Duration(milliseconds: 250), 8 | 'major-animation-curve': Curves.easeInOut, 9 | }); 10 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /equinox_visualqa/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/com/example/example/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.example; 2 | 3 | import android.os.Bundle; 4 | import io.flutter.app.FlutterActivity; 5 | import io.flutter.plugins.GeneratedPluginRegistrant; 6 | 7 | public class MainActivity extends FlutterActivity { 8 | @Override 9 | protected void onCreate(Bundle savedInstanceState) { 10 | super.onCreate(savedInstanceState); 11 | GeneratedPluginRegistrant.registerWith(this); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /example/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | import './home_page.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | void main() => runApp(MyApp()); 6 | 7 | class MyApp extends StatelessWidget { 8 | // This widget is the root of your application. 9 | @override 10 | Widget build(BuildContext context) { 11 | return EquinoxApp( 12 | theme: EqThemes.defaultDarkTheme, 13 | title: 'Flutter Demo', 14 | home: HomePage(), 15 | ); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /example/ios/Runner/AppDelegate.m: -------------------------------------------------------------------------------- 1 | #include "AppDelegate.h" 2 | #include "GeneratedPluginRegistrant.h" 3 | 4 | @implementation AppDelegate 5 | 6 | - (BOOL)application:(UIApplication *)application 7 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 8 | [GeneratedPluginRegistrant registerWithRegistry:self]; 9 | // Override point for customization after application launch. 10 | return [super application:application didFinishLaunchingWithOptions:launchOptions]; 11 | } 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /equinox_visualqa/android/app/src/main/java/com/example/equinox_visualqa/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.equinox_visualqa; 2 | 3 | import android.os.Bundle; 4 | import io.flutter.app.FlutterActivity; 5 | import io.flutter.plugins.GeneratedPluginRegistrant; 6 | 7 | public class MainActivity extends FlutterActivity { 8 | @Override 9 | protected void onCreate(Bundle savedInstanceState) { 10 | super.onCreate(savedInstanceState); 11 | GeneratedPluginRegistrant.registerWith(this); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /equinox_visualqa/ios/Runner/AppDelegate.m: -------------------------------------------------------------------------------- 1 | #include "AppDelegate.h" 2 | #include "GeneratedPluginRegistrant.h" 3 | 4 | @implementation AppDelegate 5 | 6 | - (BOOL)application:(UIApplication *)application 7 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 8 | [GeneratedPluginRegistrant registerWithRegistry:self]; 9 | // Override point for customization after application launch. 10 | return [super application:application didFinishLaunchingWithOptions:launchOptions]; 11 | } 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /equinox_visualqa/lib/utils.dart: -------------------------------------------------------------------------------- 1 | String enumToString(dynamic value) { 2 | return normalize(value.toString().split('.').last); 3 | } 4 | 5 | String normalize(String value) { 6 | String newString = ""; 7 | 8 | for (int i = 0; i < value.length; i++) { 9 | var char = value[i]; 10 | if (char.toUpperCase() == char) { 11 | newString += ' $char'; 12 | } else if (i == 0) { 13 | newString += char.toUpperCase(); 14 | } else { 15 | newString += char; 16 | } 17 | } 18 | 19 | return newString; 20 | } 21 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /equinox_visualqa/android/app/src/main/res/drawable/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 | -------------------------------------------------------------------------------- /equinox_visualqa/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/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() 4 | 5 | def plugins = new Properties() 6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') 7 | if (pluginsFile.exists()) { 8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } 9 | } 10 | 11 | plugins.each { name, path -> 12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() 13 | include ":$name" 14 | project(":$name").projectDir = pluginDirectory 15 | } 16 | -------------------------------------------------------------------------------- /equinox_visualqa/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() 4 | 5 | def plugins = new Properties() 6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') 7 | if (pluginsFile.exists()) { 8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } 9 | } 10 | 11 | plugins.each { name, path -> 12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() 13 | include ":$name" 14 | project(":$name").projectDir = pluginDirectory 15 | } 16 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | google() 4 | jcenter() 5 | } 6 | 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:3.2.1' 9 | } 10 | } 11 | 12 | allprojects { 13 | repositories { 14 | google() 15 | jcenter() 16 | } 17 | } 18 | 19 | rootProject.buildDir = '../build' 20 | subprojects { 21 | project.buildDir = "${rootProject.buildDir}/${project.name}" 22 | } 23 | subprojects { 24 | project.evaluationDependsOn(':app') 25 | } 26 | 27 | task clean(type: Delete) { 28 | delete rootProject.buildDir 29 | } 30 | -------------------------------------------------------------------------------- /equinox_visualqa/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | google() 4 | jcenter() 5 | } 6 | 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:3.2.1' 9 | } 10 | } 11 | 12 | allprojects { 13 | repositories { 14 | google() 15 | jcenter() 16 | } 17 | } 18 | 19 | rootProject.buildDir = '../build' 20 | subprojects { 21 | project.buildDir = "${rootProject.buildDir}/${project.name}" 22 | } 23 | subprojects { 24 | project.evaluationDependsOn(':app') 25 | } 26 | 27 | task clean(type: Delete) { 28 | delete rootProject.buildDir 29 | } 30 | -------------------------------------------------------------------------------- /lib/src/components/internal/clippers/inverted_cliprrect.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | 3 | class InvertedClipRRect extends CustomClipper { 4 | final BorderRadius borderRadius; 5 | 6 | InvertedClipRRect({this.borderRadius}); 7 | 8 | @override 9 | Path getClip(Size size) { 10 | var rect = new Rect.fromLTWH(0.0, 0.0, size.width, size.height); 11 | return new Path() 12 | ..addRRect(borderRadius.toRRect(rect)) 13 | ..addRect(rect) 14 | ..fillType = PathFillType.evenOdd; 15 | } 16 | 17 | @override 18 | bool shouldReclip(CustomClipper oldClipper) => false; 19 | } 20 | -------------------------------------------------------------------------------- /equinox_visualqa/README.md: -------------------------------------------------------------------------------- 1 | # equinox_visualqa 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 | -------------------------------------------------------------------------------- /equinox_visualqa/lib/state.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | import 'package:flutter/widgets.dart'; 3 | 4 | class AppState { 5 | static StyleData theme = EqThemes.defaultLightTheme; 6 | static bool isDark = false; 7 | static VoidCallback _subscriber; 8 | 9 | static toggleTheme() { 10 | if (!AppState.isDark) { 11 | AppState.theme = EqThemes.defaultDarkTheme; 12 | } else { 13 | AppState.theme = EqThemes.defaultLightTheme; 14 | } 15 | AppState.isDark = !AppState.isDark; 16 | _subscriber(); 17 | } 18 | 19 | static subscribe(VoidCallback method) { 20 | _subscriber = method; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/src/components/divider/divider.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | import 'package:flutter/widgets.dart'; 3 | 4 | /// Divider is used to divide parts of content. 5 | class EqDivider extends StatelessWidget { 6 | final Color color; 7 | final double width; 8 | const EqDivider({ 9 | Key key, 10 | this.color, 11 | this.width, 12 | }) : super(key: key); 13 | @override 14 | Widget build(BuildContext context) { 15 | final style = StaticStyle.of(context); 16 | return Container( 17 | color: color ?? style.get('divider-color'), 18 | height: width ?? style.get('divider-width'), 19 | ); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/src/components/tabs/tab_style.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | 3 | final StyleData tabStyle = StyleData({ 4 | 'tab-indicator-color': 'border-basic-color-3', 5 | 'tab-indicator-active-color': 'color-primary-500', 6 | 'tab-indicator-hover-color': 'color-primary-400', 7 | 'tab-indicator-disabled-color': Colors.transparent, 8 | 'tab-foreground-color': 'text-hint-color', 9 | 'tab-foreground-active-color': 'color-primary-500', 10 | 'tab-foreground-disabled-color': 'text-disabled-color', 11 | 'tab-text-font-family': 'button-text-font-family', 12 | 'tab-text-font-weight': 'button-text-font-weight', 13 | 'tab-text-font-size': 'button-text-medium-font-size', 14 | }); 15 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /lib/src/components/card/card_status_apperance.dart: -------------------------------------------------------------------------------- 1 | /// Controls how card's status will be displayed. 2 | /// - If [statusAppearance] is [CardStatusAppearance.header], only the header will be painted in 3 | /// the status's color. 4 | /// - If [statusAppearance] is [CardStatusAppearance.strip], the status will be displayed as 5 | /// tiny line on top of the card. 6 | /// - Otherwise, no status will be displayed. 7 | enum EqCardStatusAppearance { 8 | /// No status will be displayed 9 | none, 10 | 11 | /// A tiny line on top of the card will be painted in status's color 12 | strip, 13 | 14 | /// The header will be painted in status's color. If no header is present, nothing is painted. 15 | header, 16 | } 17 | -------------------------------------------------------------------------------- /lib/src/components/internal/scroll_behavior.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:flutter/widgets.dart'; 3 | 4 | class EquinoxScrollBehavior implements ScrollBehavior { 5 | @override 6 | Widget buildViewportChrome( 7 | BuildContext context, Widget child, AxisDirection axisDirection) { 8 | return child; 9 | } 10 | 11 | @override 12 | TargetPlatform getPlatform(BuildContext context) { 13 | return defaultTargetPlatform; 14 | } 15 | 16 | @override 17 | ScrollPhysics getScrollPhysics(BuildContext context) { 18 | return const BouncingScrollPhysics(); 19 | } 20 | 21 | @override 22 | bool shouldNotify(ScrollBehavior oldDelegate) { 23 | return false; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/src/theme/themings/support_style.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | import 'package:flutter/widgets.dart'; 3 | 4 | final StyleData supportStyle = StyleData({ 5 | 'border-radius-rectangle': 4.0, 6 | 'border-radius-semi-round': 12.0, 7 | 'outline-width': 0.375 * 16.0, 8 | 'outline-color': Colors.black.withOpacity(0.125), 9 | 'shadow': BoxShadow( 10 | offset: Offset(0.0, 8.0), 11 | blurRadius: 16.0, 12 | color: Color.fromRGBO(44, 51, 73, 0.1)), 13 | 'divider-color': 'border-basic-color-3', 14 | 'divider-width': 1.0, 15 | 'control-padding': EdgeInsets.all(0.0), 16 | 'control-description-padding': 8.0, 17 | 'border-width': 1.0, 18 | 'widget-shape': EqWidgetShape.rectangle, 19 | }); 20 | -------------------------------------------------------------------------------- /lib/src/components/internal/clippers/vertical_rectangle_clipper.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | 3 | class VerticalRectangleClipper extends CustomClipper { 4 | double verticalMultiplier; 5 | double shadowSize; 6 | 7 | VerticalRectangleClipper({this.verticalMultiplier, this.shadowSize}); 8 | 9 | @override 10 | Rect getClip(Size size) { 11 | var rect = new Rect.fromLTWH( 12 | -shadowSize, 13 | -shadowSize, 14 | size.width + shadowSize * 2, 15 | size.height + shadowSize, 16 | ); 17 | return rect; 18 | } 19 | 20 | @override 21 | bool shouldReclip(VerticalRectangleClipper oldClipper) => 22 | (oldClipper.verticalMultiplier != verticalMultiplier || 23 | oldClipper.shadowSize != shadowSize); 24 | } 25 | -------------------------------------------------------------------------------- /lib/src/components/spinner/spinner_style.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | 3 | final StyleData spinnerStyle = StyleData({ 4 | 'spinner-tiny-size': 24.0, 5 | 'spinner-small-size': 28.0, 6 | 'spinner-medium-size': 32.0, 7 | 'spinner-large-size': 36.0, 8 | 'spinner-giant-size': 40.0, 9 | 'spinner-tiny-stroke-width': 3.0, 10 | 'spinner-small-stroke-width': 4.0, 11 | 'spinner-medium-stroke-width': 5.0, 12 | 'spinner-large-stroke-width': 6.0, 13 | 'spinner-giant-stroke-width': 7.0, 14 | 'spinner-primary-color': 'color-primary-default', 15 | 'spinner-success-color': 'color-success-default', 16 | 'spinner-warning-color': 'color-warning-default', 17 | 'spinner-danger-color': 'color-danger-default', 18 | 'spinner-info-color': 'color-info-default', 19 | }); 20 | -------------------------------------------------------------------------------- /lib/src/components/spinner/spinner_painter.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:flutter/widgets.dart'; 4 | 5 | class SpinnerPainter extends CustomPainter { 6 | SpinnerPainter({this.color, this.strokeWidth}); 7 | 8 | final Color color; 9 | final double strokeWidth; 10 | 11 | @override 12 | void paint(Canvas canvas, Size size) { 13 | final Paint paint = Paint() 14 | ..color = color 15 | ..strokeWidth = strokeWidth 16 | ..style = PaintingStyle.stroke 17 | ..strokeCap = StrokeCap.round; 18 | 19 | canvas.drawArc(Offset.zero & size, 0.0, 1.5 * pi, false, paint); 20 | } 21 | 22 | @override 23 | bool shouldRepaint(SpinnerPainter oldPainter) { 24 | return oldPainter.color != color || oldPainter.strokeWidth != strokeWidth; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/src/components/app_bar/app_bar_style.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | 3 | final StyleData appBarStyle = StyleData({ 4 | "app-bar-background-color": 'background-basic-color-1', 5 | "app-bar-foreground-color": "text-basic-color", 6 | 'app-bar-shadow': 'shadow', 7 | "app-bar-title-center": true, 8 | "app-bar-title-color": "app-bar-foreground-color", 9 | "app-bar-title-font-family": "text-heading-6-font-family", 10 | "app-bar-title-font-size": "text-heading-6-font-size", 11 | "app-bar-title-font-weight": "text-heading-6-font-weight", 12 | "app-bar-subtitle-color": "text-hint-color", 13 | "app-bar-subtitle-font-family": "text-caption-2-font-family", 14 | "app-bar-subtitle-font-size": "text-caption-2-font-size", 15 | "app-bar-subtitle-font-weight": "text-caption-2-font-weight", 16 | }); 17 | -------------------------------------------------------------------------------- /lib/src/components/icon/icon.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | import 'package:equinox/src/equinox_internal.dart'; 3 | import 'package:flutter/widgets.dart'; 4 | 5 | class EqIcon extends StatelessWidget { 6 | final IconData icon; 7 | final double size; 8 | final Color color; 9 | final EqWidgetStatus status; 10 | 11 | const EqIcon( 12 | this.icon, { 13 | Key key, 14 | this.size, 15 | this.color, 16 | this.status, 17 | }) : super(key: key); 18 | @override 19 | Widget build(BuildContext context) { 20 | final style = StaticStyle.of(context); 21 | 22 | final statusColor = style.get(generateSelector(['color', status, '500'])); 23 | return Icon( 24 | icon, 25 | size: size ?? style.get('icon-size'), 26 | color: statusColor ?? color ?? style.get('icon-color'), 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/src/equinox_internal.dart: -------------------------------------------------------------------------------- 1 | export 'package:equinox/src/components/global/outlined_widget.dart'; 2 | export 'package:equinox/src/components/global/outlined_gesture_detector.dart'; 3 | 4 | export 'package:equinox/src/components/internal/clippers/double_cliprrect.dart'; 5 | export 'package:equinox/src/components/internal/clippers/inverted_cliprrect.dart'; 6 | export 'package:equinox/src/components/internal/clippers/vertical_rectangle_clipper.dart'; 7 | 8 | //export 'package:equinox/src/components/internal/internal_card.dart'; 9 | export 'package:equinox/src/components/internal/transparent_page_route.dart'; 10 | export 'package:equinox/src/components/internal/no_splash_factory.dart'; 11 | export 'package:equinox/src/components/internal/scroll_behavior.dart'; 12 | export 'package:equinox/src/theme/utils.dart'; 13 | 14 | export 'package:equinox/src/utils.dart'; 15 | -------------------------------------------------------------------------------- /equinox_visualqa/lib/main_desktop.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox_visualqa/main.dart'; 2 | import 'package:equinox_visualqa/state.dart'; 3 | import 'package:flutter/foundation.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:equinox/equinox.dart'; 6 | 7 | void main() { 8 | debugDefaultTargetPlatformOverride = TargetPlatform.fuchsia; 9 | runApp(EquinoxShowcaseApp()); 10 | } 11 | 12 | class EquinoxShowcaseApp extends StatefulWidget { 13 | @override 14 | _EquinoxShowcaseAppState createState() => _EquinoxShowcaseAppState(); 15 | } 16 | 17 | class _EquinoxShowcaseAppState extends State { 18 | @override 19 | Widget build(BuildContext context) { 20 | AppState.subscribe(() => setState(() => {})); 21 | return EquinoxApp( 22 | title: 'Flutter Demo', 23 | theme: AppState.theme, 24 | home: MainPage(), 25 | ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/src/utils.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | import 'package:flutter/widgets.dart'; 3 | 4 | class EqToggleableDesciptionUtils { 5 | static List buildListWithDescription( 6 | {Widget main, 7 | double padding, 8 | Widget description, 9 | EqPositioning descriptionPosition}) { 10 | if (description == null || descriptionPosition == EqPositioning.none) { 11 | return [main]; 12 | } 13 | if (descriptionPosition == EqPositioning.left) { 14 | return [ 15 | Flexible(child: description), 16 | SizedBox(width: padding), 17 | main, 18 | ]; 19 | } else if (descriptionPosition == EqPositioning.right) { 20 | return [ 21 | main, 22 | SizedBox(width: padding), 23 | Flexible(child: description), 24 | ]; 25 | } 26 | return null; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /example/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /equinox_visualqa/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /lib/src/components/select/select_item.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | /// Represents an item in Select list. 5 | class EqSelectItem { 6 | /// Icon to display alongisde the title and subtitle. 7 | final IconData icon; 8 | 9 | /// Main information. 10 | final String title; 11 | 12 | /// Additional information. 13 | final String subtitle; 14 | 15 | /// Underlying value that this item holds. 16 | final T value; 17 | 18 | EqSelectItem({ 19 | @required this.title, 20 | @required this.value, 21 | this.icon, 22 | this.subtitle, 23 | }); 24 | 25 | double caluclateHeight(StaticStyleState style) { 26 | double titleHeight = 27 | (title != null) ? style.get('list-item-title-font-size') : 0.0; 28 | double subtitleHeight = 29 | (subtitle != null) ? style.get('list-item-subtitle-font-size') : 0.0; 30 | 31 | return 36.0 + titleHeight + subtitleHeight; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Erzhan 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. 22 | -------------------------------------------------------------------------------- /lib/src/components/global/theme.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | import 'package:equinox/src/equinox_internal.dart'; 3 | import 'package:flutter/widgets.dart'; 4 | 5 | import 'package:flutter/material.dart' as MaterialDesign; 6 | 7 | class EqTheme extends StatelessWidget { 8 | final StyleData theme; 9 | final Widget child; 10 | 11 | const EqTheme({Key key, this.theme, this.child}) : super(key: key); 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return MaterialDesign.Theme( 16 | data: MaterialDesign.ThemeData( 17 | splashFactory: const NoSplashFactory(), 18 | ), 19 | child: ScrollConfiguration( 20 | behavior: EquinoxScrollBehavior(), 21 | child: StaticStyle( 22 | data: theme, 23 | child: AnimatedDefaultTextStyle( 24 | duration: theme.get('major-animation-duration'), 25 | curve: theme.get('major-animation-curve'), 26 | style: TextStyle(color: theme.get('text-basic-color')), 27 | child: child, 28 | ), 29 | ), 30 | )); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/src/components/toast/toast_data.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | import 'package:flutter/widgets.dart'; 3 | 4 | /// A set of data to display in a toast. 5 | class EqToast { 6 | /// Message gets displayed as the largest element in the tab. 7 | final String message; 8 | 9 | /// Subtitle provides some additional information besides [message]. Optional. 10 | final String subtitle; 11 | 12 | /// Icon to display alongside [message]. Optional. 13 | final IconData icon; 14 | 15 | /// Status of this toast 16 | final EqWidgetStatus status; 17 | 18 | /// The shape of this toast. Uses [EqThemeData.defaultWidgetShape] as default. 19 | final EqWidgetShape shape; 20 | 21 | /// Duration of this toast. After [duration] elapses, tab will hide automatically. 22 | final Duration duration; 23 | 24 | /// Gets called when user taps the toast. Optional. 25 | final VoidCallback onTap; 26 | 27 | const EqToast({ 28 | @required this.message, 29 | this.subtitle, 30 | this.icon, 31 | this.onTap, 32 | this.status, 33 | this.shape, 34 | this.duration = const Duration(seconds: 3), 35 | }); 36 | } 37 | -------------------------------------------------------------------------------- /equinox_visualqa/test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:equinox_visualqa/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(EquinoxShowcaseApp()); 17 | 18 | // Verify that our counter starts at 0. 19 | expect(find.text('0'), findsOneWidget); 20 | expect(find.text('1'), findsNothing); 21 | 22 | // Tap the '+' icon and trigger a frame. 23 | await tester.tap(find.byIcon(Icons.add)); 24 | await tester.pump(); 25 | 26 | // Verify that our counter has incremented. 27 | expect(find.text('0'), findsNothing); 28 | expect(find.text('1'), findsOneWidget); 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /lib/src/components/global/outlined_gesture_detector.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | import 'package:flutter/widgets.dart'; 3 | 4 | class OutlinedGestureDetector extends StatelessWidget { 5 | final Widget child; 6 | final Function(bool) onOutlineChange; 7 | final VoidCallback onTap; 8 | 9 | const OutlinedGestureDetector( 10 | {Key key, this.onOutlineChange, this.onTap, this.child}) 11 | : super(key: key); 12 | 13 | void onTapDown(data) { 14 | onOutlineChange(true); 15 | } 16 | 17 | void clearOutline(Duration delay) { 18 | Future.delayed(delay, () => onOutlineChange(false)); 19 | } 20 | 21 | @override 22 | Widget build(BuildContext context) { 23 | var style = StaticStyle.of(context); 24 | return GestureDetector( 25 | behavior: HitTestBehavior.opaque, 26 | onTap: onTap, 27 | onTapDown: (onTap != null) ? onTapDown : null, 28 | onTapUp: (onTap != null) 29 | ? (_) => clearOutline(style.get('minor-animation-duration')) 30 | : null, 31 | onTapCancel: (onTap != null) 32 | ? () => clearOutline(style.get('minor-animation-duration')) 33 | : null, 34 | child: child, 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lib/src/components/internal/no_splash_factory.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class NoSplashFactory implements InteractiveInkFeatureFactory { 4 | const NoSplashFactory(); 5 | 6 | InteractiveInkFeature create( 7 | {MaterialInkController controller, 8 | RenderBox referenceBox, 9 | Offset position, 10 | Color color, 11 | TextDirection textDirection, 12 | bool containedInkWell = false, 13 | rectCallback, 14 | BorderRadius borderRadius, 15 | ShapeBorder customBorder, 16 | double radius, 17 | VoidCallback onRemoved}) { 18 | return new NoSplash( 19 | controller: controller, 20 | referenceBox: referenceBox, 21 | ); 22 | } 23 | } 24 | 25 | class NoSplash extends InteractiveInkFeature { 26 | NoSplash({ 27 | @required MaterialInkController controller, 28 | @required RenderBox referenceBox, 29 | }) : super( 30 | controller: controller, 31 | referenceBox: referenceBox, 32 | ) { 33 | assert(controller != null); 34 | assert(referenceBox != null); 35 | controller.addInkFeature(this); 36 | } 37 | 38 | @override 39 | void paintFeature(Canvas canvas, Matrix4 transform) {} 40 | } 41 | -------------------------------------------------------------------------------- /lib/src/components/internal/clippers/double_cliprrect.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | 3 | class DoubleClipRRect extends CustomClipper { 4 | final BorderRadius borderRadius; 5 | final double outilneVerticalWidth; 6 | final double outlineHorizontalWidth; 7 | 8 | DoubleClipRRect({ 9 | this.outilneVerticalWidth, 10 | this.outlineHorizontalWidth, 11 | this.borderRadius, 12 | }); 13 | 14 | @override 15 | Path getClip(Size size) { 16 | var rect = new Rect.fromLTWH(0.0, 0.0, size.width, size.height); 17 | var innerRect = new Rect.fromLTRB( 18 | outlineHorizontalWidth, 19 | outilneVerticalWidth, 20 | size.width - outlineHorizontalWidth, 21 | size.height - outilneVerticalWidth, 22 | ); 23 | 24 | return new Path() 25 | ..addRRect(borderRadius.toRRect(rect)) 26 | ..addRRect(borderRadius.toRRect(innerRect)) 27 | ..fillType = PathFillType.evenOdd; 28 | } 29 | 30 | @override 31 | bool shouldReclip(DoubleClipRRect oldClipper) => 32 | this.borderRadius != oldClipper.borderRadius || 33 | this.outilneVerticalWidth != oldClipper.outilneVerticalWidth || 34 | this.outlineHorizontalWidth != oldClipper.outlineHorizontalWidth; 35 | } 36 | -------------------------------------------------------------------------------- /lib/src/components/toast/toast_style.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | import 'package:flutter/widgets.dart'; 3 | 4 | StyleData _generateForStatus(String status) { 5 | return StyleData({ 6 | 'toast-$status-background-color': 'color-$status-default', 7 | 'toast-$status-foreground-color': 'text-control-color', 8 | 'toast-$status-icon-color': 'toast-$status-background-color', 9 | }); 10 | } 11 | 12 | final StyleData toastStyle = StyleData({ 13 | 'toast-shadow': 'shadow', 14 | 'toast-icon-size': 'icon-size', 15 | 'toast-icon-padding': EdgeInsets.all(8.0), 16 | 'toast-title-font-family': 'text-subtitle-font-family', 17 | 'toast-title-font-weight': 'text-subtitle-font-weight', 18 | 'toast-title-font-size': 'text-subtitle-font-size', 19 | 'toast-subtitle-font-family': 'text-paragraph-font-family', 20 | 'toast-subtitle-font-weight': 'text-paragraph-font-weight', 21 | 'toast-subtitle-font-size': 'text-paragraph-font-size', 22 | 'toast-background-color': 'background-basic-color-1', 23 | 'toast-foreground-color': 'text-basic-color', 24 | 'toast-icon-color': 'text-basic-color', 25 | }) 26 | ..inject(_generateForStatus('primary')) 27 | ..inject(_generateForStatus('success')) 28 | ..inject(_generateForStatus('warning')) 29 | ..inject(_generateForStatus('danger')) 30 | ..inject(_generateForStatus('info')); 31 | -------------------------------------------------------------------------------- /equinox_visualqa/desktop/cmd/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | _ "image/png" 7 | "os" 8 | "path/filepath" 9 | "strings" 10 | 11 | "github.com/go-flutter-desktop/go-flutter" 12 | "github.com/pkg/errors" 13 | ) 14 | 15 | // vmArguments may be set by hover at compile-time 16 | var vmArguments string 17 | 18 | func main() { 19 | // DO NOT EDIT, add options in options.go 20 | mainOptions := []flutter.Option{ 21 | flutter.OptionVMArguments(strings.Split(vmArguments, ";")), 22 | flutter.WindowIcon(iconProvider), 23 | } 24 | err := flutter.Run(append(options, mainOptions...)...) 25 | if err != nil { 26 | fmt.Println(err) 27 | os.Exit(1) 28 | } 29 | } 30 | 31 | func iconProvider() ([]image.Image, error) { 32 | execPath, err := os.Executable() 33 | if err != nil { 34 | return nil, errors.Wrap(err, "failed to resolve executable path") 35 | } 36 | execPath, err = filepath.EvalSymlinks(execPath) 37 | if err != nil { 38 | return nil, errors.Wrap(err, "failed to eval symlinks for executable path") 39 | } 40 | imgFile, err := os.Open(filepath.Join(filepath.Dir(execPath), "assets", "icon.png")) 41 | if err != nil { 42 | return nil, errors.Wrap(err, "failed to open assets/icon.png") 43 | } 44 | img, _, err := image.Decode(imgFile) 45 | if err != nil { 46 | return nil, errors.Wrap(err, "failed to decode image") 47 | } 48 | return []image.Image{img}, nil 49 | } 50 | -------------------------------------------------------------------------------- /lib/src/components/card/card_style.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | import 'package:flutter/widgets.dart'; 3 | 4 | StyleData _getHeaderStyle(String status) { 5 | return StyleData({ 6 | 'card-header-$status-background-color': 'color-$status-default', 7 | 'card-header-$status-text-color': 'text-control-color', 8 | }); 9 | } 10 | 11 | final StyleData cardStyle = StyleData({ 12 | 'card-background-color': 'background-basic-color-1', 13 | 'card-text-color': 'text-basic-color', 14 | 'card-text-font-family': 'text-paragraph-font-family', 15 | 'card-text-font-weight': 'text-paragraph-font-weight', 16 | 'card-text-font-size': 'text-paragraph-font-size', 17 | 'card-border-width': 0.0, 18 | 'card-border-color': Colors.transparent, 19 | 'card-shape': 'widget-shape', 20 | 'card-padding': const EdgeInsets.symmetric(vertical: 16.0, horizontal: 20.0), 21 | 'card-shadow': 'shadow', 22 | 'card-divider-color': 'divider-color', 23 | 'card-divider-width': 'divider-width', 24 | 'card-header-background-color': 'card-background-color', 25 | 'card-header-text-color': 'text-basic-color', 26 | 'card-header-text-font-family': 'text-subtitle-font-family', 27 | 'card-header-text-font-weight': 'text-subtitle-font-weight', 28 | 'card-header-text-font-size': 'text-subtitle-font-size', 29 | }) 30 | ..inject(_getHeaderStyle('primary')) 31 | ..inject(_getHeaderStyle('success')) 32 | ..inject(_getHeaderStyle('warning')) 33 | ..inject(_getHeaderStyle('danger')) 34 | ..inject(_getHeaderStyle('info')); 35 | -------------------------------------------------------------------------------- /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 | # Visual Studio Code related 19 | .vscode/ 20 | 21 | # Flutter/Dart/Pub related 22 | **/doc/api/ 23 | .dart_tool/ 24 | .flutter-plugins 25 | .packages 26 | .pub-cache/ 27 | .pub/ 28 | /build/ 29 | 30 | # Android related 31 | **/android/**/gradle-wrapper.jar 32 | **/android/.gradle 33 | **/android/captures/ 34 | **/android/gradlew 35 | **/android/gradlew.bat 36 | **/android/local.properties 37 | **/android/**/GeneratedPluginRegistrant.java 38 | 39 | # iOS/XCode related 40 | **/ios/**/*.mode1v3 41 | **/ios/**/*.mode2v3 42 | **/ios/**/*.moved-aside 43 | **/ios/**/*.pbxuser 44 | **/ios/**/*.perspectivev3 45 | **/ios/**/*sync/ 46 | **/ios/**/.sconsign.dblite 47 | **/ios/**/.tags* 48 | **/ios/**/.vagrant/ 49 | **/ios/**/DerivedData/ 50 | **/ios/**/Icon? 51 | **/ios/**/Pods/ 52 | **/ios/**/.symlinks/ 53 | **/ios/**/profile 54 | **/ios/**/xcuserdata 55 | **/ios/.generated/ 56 | **/ios/Flutter/App.framework 57 | **/ios/Flutter/Flutter.framework 58 | **/ios/Flutter/Generated.xcconfig 59 | **/ios/Flutter/app.flx 60 | **/ios/Flutter/app.zip 61 | **/ios/Flutter/flutter_assets/ 62 | **/ios/ServiceDefinitions.json 63 | **/ios/Runner/GeneratedPluginRegistrant.* 64 | 65 | # Exceptions to above rules. 66 | !**/ios/**/default.mode1v3 67 | !**/ios/**/default.mode2v3 68 | !**/ios/**/default.pbxuser 69 | !**/ios/**/default.perspectivev3 70 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 71 | -------------------------------------------------------------------------------- /equinox_visualqa/.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 | # Visual Studio Code related 19 | .vscode/ 20 | 21 | # Flutter/Dart/Pub related 22 | **/doc/api/ 23 | .dart_tool/ 24 | .flutter-plugins 25 | .packages 26 | .pub-cache/ 27 | .pub/ 28 | /build/ 29 | 30 | # Android related 31 | **/android/**/gradle-wrapper.jar 32 | **/android/.gradle 33 | **/android/captures/ 34 | **/android/gradlew 35 | **/android/gradlew.bat 36 | **/android/local.properties 37 | **/android/**/GeneratedPluginRegistrant.java 38 | 39 | # iOS/XCode related 40 | **/ios/**/*.mode1v3 41 | **/ios/**/*.mode2v3 42 | **/ios/**/*.moved-aside 43 | **/ios/**/*.pbxuser 44 | **/ios/**/*.perspectivev3 45 | **/ios/**/*sync/ 46 | **/ios/**/.sconsign.dblite 47 | **/ios/**/.tags* 48 | **/ios/**/.vagrant/ 49 | **/ios/**/DerivedData/ 50 | **/ios/**/Icon? 51 | **/ios/**/Pods/ 52 | **/ios/**/.symlinks/ 53 | **/ios/**/profile 54 | **/ios/**/xcuserdata 55 | **/ios/.generated/ 56 | **/ios/Flutter/App.framework 57 | **/ios/Flutter/Flutter.framework 58 | **/ios/Flutter/Generated.xcconfig 59 | **/ios/Flutter/app.flx 60 | **/ios/Flutter/app.zip 61 | **/ios/Flutter/flutter_assets/ 62 | **/ios/ServiceDefinitions.json 63 | **/ios/Runner/GeneratedPluginRegistrant.* 64 | 65 | # Exceptions to above rules. 66 | !**/ios/**/default.mode1v3 67 | !**/ios/**/default.mode2v3 68 | !**/ios/**/default.pbxuser 69 | !**/ios/**/default.perspectivev3 70 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 71 | -------------------------------------------------------------------------------- /lib/src/components/toast/toast_reveal.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | 3 | class ToastRevealAnimationWidget extends StatelessWidget { 4 | final Widget child; 5 | final Animation animation; 6 | final outlineWidth; 7 | 8 | const ToastRevealAnimationWidget({ 9 | Key key, 10 | this.animation, 11 | this.child, 12 | this.outlineWidth, 13 | }) : super(key: key); 14 | @override 15 | Widget build(BuildContext context) { 16 | return ClipRect( 17 | clipper: ToastRevealAnimationClipper( 18 | animation.value, 19 | outlineWidth, 20 | ), 21 | child: Align( 22 | alignment: Alignment.bottomRight, 23 | widthFactor: animation.value, 24 | heightFactor: animation.value, 25 | child: child, 26 | ), 27 | ); 28 | } 29 | } 30 | 31 | class ToastRevealAnimationClipper extends CustomClipper { 32 | final double sizeMultiplier; 33 | final double outlineWidth; 34 | 35 | ToastRevealAnimationClipper( 36 | this.sizeMultiplier, 37 | this.outlineWidth, 38 | ); 39 | @override 40 | Rect getClip(Size size) { 41 | var sizeMultiplied = size * sizeMultiplier; 42 | Rect rect = Rect.fromLTRB( 43 | size.width - sizeMultiplied.width - outlineWidth, 44 | size.height - sizeMultiplied.height - outlineWidth, 45 | size.width + outlineWidth, 46 | size.height + outlineWidth, 47 | ); 48 | return rect; 49 | } 50 | 51 | @override 52 | bool shouldReclip(ToastRevealAnimationClipper oldClipper) => 53 | oldClipper.sizeMultiplier != sizeMultiplier || 54 | oldClipper.outlineWidth != outlineWidth; 55 | } 56 | -------------------------------------------------------------------------------- /equinox_visualqa/lib/components/spinner.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:equinox_visualqa/management/showcase_state.dart'; 4 | 5 | class SpinnerShowcase extends StatefulWidget { 6 | @override 7 | _SpinnerShowcaseState createState() => _SpinnerShowcaseState(); 8 | } 9 | 10 | class _SpinnerShowcaseState extends ShowcaseState { 11 | @override 12 | Widget playgroundBuilder() => SizedBox(); 13 | 14 | @override 15 | String get showcaseName => 'Spinners'; 16 | 17 | @override 18 | List get showcases => [ 19 | ShowcaseWidgetData( 20 | title: 'Spinner', 21 | builder: () => EqSpinner(), 22 | ), 23 | ShowcaseWidgetData( 24 | title: 'Spinner colors', 25 | builder: () => Wrap( 26 | spacing: 16.0, 27 | runSpacing: 16.0, 28 | alignment: WrapAlignment.start, 29 | children: EqWidgetStatus.values 30 | .map((status) => EqSpinner( 31 | status: status, 32 | )) 33 | .toList(), 34 | ), 35 | ), 36 | ShowcaseWidgetData( 37 | title: 'Spinner sizes', 38 | builder: () => Wrap( 39 | spacing: 16.0, 40 | runSpacing: 16.0, 41 | alignment: WrapAlignment.start, 42 | children: EqWidgetSize.values.reversed 43 | .map((size) => EqSpinner( 44 | size: size, 45 | )) 46 | .toList(), 47 | ), 48 | ), 49 | ]; 50 | } 51 | -------------------------------------------------------------------------------- /example/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 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 | -------------------------------------------------------------------------------- /equinox_visualqa/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | equinox_visualqa 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /example/ios/Runner/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 | -------------------------------------------------------------------------------- /equinox_visualqa/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 | -------------------------------------------------------------------------------- /equinox_visualqa/desktop/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 2 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 3 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 4 | github.com/go-flutter-desktop/go-flutter v0.24.1 h1:EmWLFUaxxfF03TJrBt7tohOBcds6cw16ximKUX6IKTY= 5 | github.com/go-flutter-desktop/go-flutter v0.24.1/go.mod h1:GZYxHYp7lRnt3imJV1d8EWleMv5q9J4S2ONNEqpPOfo= 6 | github.com/go-flutter-desktop/go-flutter v0.25.0 h1:h7V5S1XFrAroagVG77NCpUTJrfRxOX0lxzelM6qoJIc= 7 | github.com/go-flutter-desktop/go-flutter v0.25.0/go.mod h1:GZYxHYp7lRnt3imJV1d8EWleMv5q9J4S2ONNEqpPOfo= 8 | github.com/go-flutter-desktop/go-flutter v0.26.0 h1:Sja3JRKzAPoi0h8hOQFQQ3wOnIXcFwBJTrDetC2ErQI= 9 | github.com/go-flutter-desktop/go-flutter v0.26.0/go.mod h1:GZYxHYp7lRnt3imJV1d8EWleMv5q9J4S2ONNEqpPOfo= 10 | github.com/go-gl/glfw v0.0.0-20190519095719-e6da0acd62b1 h1:noz9OnjV5PMOZWNOI+y1cS5rnxuJfpY6leIgQEEdBQw= 11 | github.com/go-gl/glfw v0.0.0-20190519095719-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= 12 | github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= 13 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 14 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 15 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 16 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 17 | github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= 18 | github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= 19 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 20 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 9 | 13 | 20 | 24 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Testing 2 | /ios/ 3 | /android/ 4 | /lib/main.dart 5 | /lib/home_page.dart 6 | 7 | # Miscellaneous 8 | *.class 9 | *.log 10 | *.pyc 11 | *.swp 12 | .DS_Store 13 | .atom/ 14 | .buildlog/ 15 | .history 16 | .svn/ 17 | screenshots/ 18 | 19 | # IntelliJ related 20 | *.iml 21 | *.ipr 22 | *.iws 23 | .idea/ 24 | 25 | # The .vscode folder contains launch configuration and tasks you configure in 26 | # VS Code which you may wish to be included in version control, so this line 27 | # is commented out by default. 28 | #.vscode/ 29 | 30 | # Flutter/Dart/Pub related 31 | **/doc/api/ 32 | .dart_tool/ 33 | .flutter-plugins 34 | .packages 35 | .pub-cache/ 36 | .pub/ 37 | /build/ 38 | 39 | # Android related 40 | **/android/**/gradle-wrapper.jar 41 | **/android/.gradle 42 | **/android/captures/ 43 | **/android/gradlew 44 | **/android/gradlew.bat 45 | **/android/local.properties 46 | **/android/**/GeneratedPluginRegistrant.java 47 | 48 | # iOS/XCode related 49 | **/ios/**/*.mode1v3 50 | **/ios/**/*.mode2v3 51 | **/ios/**/*.moved-aside 52 | **/ios/**/*.pbxuser 53 | **/ios/**/*.perspectivev3 54 | **/ios/**/*sync/ 55 | **/ios/**/.sconsign.dblite 56 | **/ios/**/.tags* 57 | **/ios/**/.vagrant/ 58 | **/ios/**/DerivedData/ 59 | **/ios/**/Icon? 60 | **/ios/**/Pods/ 61 | **/ios/**/.symlinks/ 62 | **/ios/**/profile 63 | **/ios/**/xcuserdata 64 | **/ios/.generated/ 65 | **/ios/Flutter/App.framework 66 | **/ios/Flutter/Flutter.framework 67 | **/ios/Flutter/Generated.xcconfig 68 | **/ios/Flutter/app.flx 69 | **/ios/Flutter/app.zip 70 | **/ios/Flutter/flutter_assets/ 71 | **/ios/ServiceDefinitions.json 72 | **/ios/Runner/GeneratedPluginRegistrant.* 73 | 74 | # Exceptions to above rules. 75 | !**/ios/**/default.mode1v3 76 | !**/ios/**/default.mode2v3 77 | !**/ios/**/default.pbxuser 78 | !**/ios/**/default.perspectivev3 79 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 80 | 81 | .vscode/ -------------------------------------------------------------------------------- /equinox_visualqa/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 9 | 13 | 20 | 24 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /equinox_visualqa/lib/management/showcase_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | import 'package:equinox_visualqa/state.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter/widgets.dart'; 5 | export 'package:equinox_visualqa/management/interactive_playground.dart'; 6 | 7 | class ShowcaseWidgetData { 8 | final String title; 9 | final Widget Function() builder; 10 | final bool override; 11 | 12 | ShowcaseWidgetData({ 13 | this.title, 14 | this.builder, 15 | this.override = false, 16 | }); 17 | } 18 | 19 | abstract class ShowcaseState extends State { 20 | List get showcases; 21 | String get showcaseName; 22 | Widget playgroundBuilder(); 23 | 24 | List get children { 25 | var items = []; 26 | 27 | showcases.forEach((showcase) { 28 | items.add( 29 | showcase.override 30 | ? showcase.builder() 31 | : EqCard( 32 | statusAppearance: EqCardStatusAppearance.none, 33 | header: Text(showcase.title), 34 | child: showcase.builder(), 35 | ), 36 | ); 37 | items.add(SizedBox(height: 16.0)); 38 | }); 39 | 40 | items.add(playgroundBuilder()); 41 | return items; 42 | } 43 | 44 | @override 45 | Widget build(BuildContext context) { 46 | return EqLayout( 47 | appBar: EqAppBar( 48 | title: 'Showcase', 49 | subtitle: showcaseName, 50 | centerTitle: true, 51 | actions: [ 52 | EqIconButton( 53 | icon: EvaIcons.sunOutline, 54 | onTap: AppState.toggleTheme, 55 | appearance: EqWidgetAppearance.ghost, 56 | ), 57 | ], 58 | ), 59 | child: ListView( 60 | padding: const EdgeInsets.all(16.0), 61 | children: children, 62 | ), 63 | ); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /lib/src/components/internal/transparent_page_route.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | import 'package:flutter/widgets.dart'; 3 | 4 | class TransparentPageRoute extends PageRoute { 5 | TransparentPageRoute({ 6 | @required this.builder, 7 | RouteSettings settings, 8 | }) : assert(builder != null), 9 | super( 10 | settings: settings, 11 | fullscreenDialog: false, 12 | ); 13 | 14 | final WidgetBuilder builder; 15 | 16 | @override 17 | bool get opaque => false; 18 | 19 | @override 20 | Color get barrierColor => null; 21 | 22 | @override 23 | String get barrierLabel => null; 24 | 25 | @override 26 | bool get maintainState => true; 27 | 28 | @override 29 | Duration get transitionDuration => Duration(milliseconds: 250); 30 | 31 | @override 32 | Widget buildPage(BuildContext context, Animation animation, 33 | Animation secondaryAnimation) { 34 | final result = builder(context); 35 | return Semantics( 36 | scopesRoute: true, 37 | explicitChildNodes: true, 38 | child: AnimatedBuilder( 39 | animation: animation, 40 | builder: (BuildContext context, Widget child) { 41 | final style = StaticStyle.of(context); 42 | return Opacity( 43 | opacity: 44 | style.get('minor-animation-curve').transform(animation.value), 45 | child: GestureDetector( 46 | onTap: () => Navigator.pop(context), 47 | child: Container( 48 | decoration: BoxDecoration( 49 | color: Colors.black.withOpacity(0.75), 50 | ), 51 | child: Center( 52 | child: GestureDetector( 53 | onTap: () {}, 54 | child: result, 55 | ), 56 | ), 57 | ), 58 | ), 59 | ); 60 | }), 61 | ); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /lib/src/components/text/text_params.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | import 'package:flutter/widgets.dart'; 3 | 4 | enum EqTextState { 5 | basic, 6 | alternate, 7 | disabled, 8 | hint, 9 | control, 10 | } 11 | 12 | enum EqTextStyle { 13 | caption1, 14 | caption2, 15 | heading1, 16 | heading2, 17 | heading3, 18 | heading4, 19 | heading5, 20 | heading6, 21 | label, 22 | paragraph1, 23 | paragraph2, 24 | subtitle1, 25 | subtitle2, 26 | } 27 | 28 | class EqTextUtils { 29 | static String getStyleName({EqTextStyle style}) { 30 | switch (style) { 31 | case EqTextStyle.caption1: 32 | return 'caption'; 33 | case EqTextStyle.caption2: 34 | return 'caption-2'; 35 | case EqTextStyle.heading1: 36 | return 'heading-1'; 37 | case EqTextStyle.heading2: 38 | return 'heading-2'; 39 | case EqTextStyle.heading3: 40 | return 'heading-3'; 41 | case EqTextStyle.heading4: 42 | return 'heading-4'; 43 | case EqTextStyle.heading5: 44 | return 'heading-5'; 45 | case EqTextStyle.heading6: 46 | return 'heading-6'; 47 | case EqTextStyle.label: 48 | return 'label'; 49 | case EqTextStyle.paragraph1: 50 | return 'paragraph'; 51 | case EqTextStyle.paragraph2: 52 | return 'paragraph-2'; 53 | case EqTextStyle.subtitle1: 54 | return 'subtitle'; 55 | case EqTextStyle.subtitle2: 56 | return 'subtitle-2'; 57 | default: 58 | return 'subtitle-2'; 59 | } 60 | } 61 | 62 | static TextStyle getTextStyle( 63 | {EqTextStyle style, StaticStyleState styleData}) { 64 | final styleName = 'text-${getStyleName(style: style)}'; 65 | final fontFamily = styleData.get('$styleName-font-family'); 66 | final fontSize = styleData.get('$styleName-font-size'); 67 | final fontWeight = styleData.get('$styleName-font-weight'); 68 | 69 | return TextStyle( 70 | fontFamily: fontFamily, 71 | fontSize: fontSize, 72 | fontWeight: fontWeight, 73 | ); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /lib/src/components/tab_bar/tab_bar.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | import 'package:flutter/widgets.dart'; 3 | 4 | /// EqTabBar is generally put inside [EqAppBar.bottom] or [EqLayout.bottomTabBar]. It can be used to display various 5 | /// paths or pages. Use [EqTabBar.bottom()] if you want to make it a BottomTabBar, and [EqTabBar.top()] otherwise. 6 | /// 7 | /// [tabs] must not be null. 8 | class EqTabBar extends StatelessWidget implements PreferredSizeWidget { 9 | /// Index of a tab that is selected by default. 10 | final int defaultSelected; 11 | 12 | /// This method is called when a tab is selected. Can be `null` to make all tabs disabled. 13 | final Function(int) onSelect; 14 | 15 | /// List of all tabs. See [EqTabData] for more; 16 | final List tabs; 17 | 18 | /// Whether this is a top tabbar or bottom tab bar. 19 | final EqVerticalPositioning position; 20 | 21 | const EqTabBar({ 22 | Key key, 23 | this.defaultSelected, 24 | @required this.onSelect, 25 | @required this.tabs, 26 | this.position = EqVerticalPositioning.top, 27 | }) : super(key: key); 28 | 29 | const EqTabBar.top({ 30 | Key key, 31 | this.defaultSelected, 32 | @required this.onSelect, 33 | @required this.tabs, 34 | }) : this.position = EqVerticalPositioning.top, 35 | super(key: key); 36 | 37 | const EqTabBar.bottom({ 38 | Key key, 39 | this.defaultSelected, 40 | @required this.onSelect, 41 | @required this.tabs, 42 | }) : this.position = EqVerticalPositioning.bottom, 43 | super(key: key); 44 | 45 | @override 46 | Widget build(BuildContext context) { 47 | return EqTabs( 48 | onSelect: onSelect, 49 | tabs: tabs, 50 | defaultSelected: defaultSelected, 51 | showPagerIndicator: position == EqVerticalPositioning.top ? true : null, 52 | pagerIndicatorPosition: this.position == EqVerticalPositioning.top 53 | ? EqVerticalPositioning.bottom 54 | : EqVerticalPositioning.top, 55 | ); 56 | } 57 | 58 | @override 59 | Size get preferredSize => Size.fromHeight(48.0); 60 | } 61 | -------------------------------------------------------------------------------- /lib/src/components/list_item/list_item_style.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | 3 | StyleData _getForStatus(String status) { 4 | return StyleData({ 5 | 'list-item-title-$status-color': 'text-basic-color', 6 | 'list-item-title-$status-active-color': 'text-$status-color', 7 | 'list-item-title-$status-focused-color': 'color-$status-500', 8 | 'list-item-subtitle-$status-color': 'text-hint-color', 9 | 'list-item-subtitle-$status-active-color': 'color-$status-300', 10 | 'list-item-subtitle-$status-focused-color': 'color-$status-400', 11 | 'list-item-icon-$status-color': 'text-hint-color', 12 | 'list-item-icon-$status-active-color': 'color-$status-300', 13 | 'list-item-icon-$status-focused-color': 'color-$status-400', 14 | }); 15 | } 16 | 17 | final StyleData listItemStyle = StyleData({ 18 | 'list-item-title-font-family': 'text-subtitle-font-family', 19 | 'list-item-title-font-size': 'text-subtitle-font-size', 20 | 'list-item-title-font-weight': 'text-subtitle-font-weight', 21 | 'list-item-subtitle-font-family': 'text-subtitle-font-family', 22 | 'list-item-subtitle-font-size': 'text-subtitle-font-size', 23 | 'list-item-subtitle-font-weight': 'text-subtitle-font-weight', 24 | 'list-item-title-disabled-color': 'text-disabled-color', 25 | 'list-item-subtitle-disabled-color': 'text-disabled-color', 26 | 'list-item-icon-disabled-color': 'text-disabled-color', 27 | 'list-item-title-color': 'text-basic-color', 28 | 'list-item-title-active-color': 'text-primary-color', 29 | 'list-item-title-focused-color': 'color-primary-500', 30 | 'list-item-subtitle-color': 'text-hint-color', 31 | 'list-item-subtitle-active-color': 'color-primary-hover', 32 | 'list-item-subtitle-focused-color': 'color-primary-400', 33 | 'list-item-icon-color': 'text-hint-color', 34 | 'list-item-icon-active-color': 'color-primary-hover', 35 | 'list-item-icon-focused-color': 'color-primary-400', 36 | }) 37 | ..inject(_getForStatus('primary')) 38 | ..inject(_getForStatus('success')) 39 | ..inject(_getForStatus('warning')) 40 | ..inject(_getForStatus('danger')) 41 | ..inject(_getForStatus('info')); 42 | -------------------------------------------------------------------------------- /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 from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 26 | 27 | android { 28 | compileSdkVersion 28 29 | 30 | lintOptions { 31 | disable 'InvalidPackage' 32 | } 33 | 34 | defaultConfig { 35 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 36 | applicationId "com.example.example" 37 | minSdkVersion 16 38 | targetSdkVersion 28 39 | versionCode flutterVersionCode.toInteger() 40 | versionName flutterVersionName 41 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 42 | } 43 | 44 | buildTypes { 45 | release { 46 | // TODO: Add your own signing config for the release build. 47 | // Signing with the debug keys for now, so `flutter run --release` works. 48 | signingConfig signingConfigs.debug 49 | } 50 | } 51 | } 52 | 53 | flutter { 54 | source '../..' 55 | } 56 | 57 | dependencies { 58 | testImplementation 'junit:junit:4.12' 59 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 60 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 61 | } 62 | -------------------------------------------------------------------------------- /equinox_visualqa/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 from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 26 | 27 | android { 28 | compileSdkVersion 28 29 | 30 | lintOptions { 31 | disable 'InvalidPackage' 32 | } 33 | 34 | defaultConfig { 35 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 36 | applicationId "com.example.equinox_visualqa" 37 | minSdkVersion 16 38 | targetSdkVersion 28 39 | versionCode flutterVersionCode.toInteger() 40 | versionName flutterVersionName 41 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 42 | } 43 | 44 | buildTypes { 45 | release { 46 | // TODO: Add your own signing config for the release build. 47 | // Signing with the debug keys for now, so `flutter run --release` works. 48 | signingConfig signingConfigs.debug 49 | } 50 | } 51 | } 52 | 53 | flutter { 54 | source '../..' 55 | } 56 | 57 | dependencies { 58 | testImplementation 'junit:junit:4.12' 59 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 60 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 61 | } 62 | -------------------------------------------------------------------------------- /lib/src/components/progress_bar/progress_bar_style.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | 3 | StyleData _generateForStyle(String status) { 4 | return StyleData({ 5 | 'progress-bar-$status-background-color': 'progress-bar-background-color', 6 | 'progress-bar-$status-progress-color': 'color-$status-default', 7 | 'progress-bar-$status-text-color': 'progress-bar-text-color', 8 | }); 9 | } 10 | 11 | final StyleData progressBarStyle = StyleData({ 12 | 'progress-bar-tiny-height': 16.0, 13 | 'progress-bar-small-height': 20.0, 14 | 'progress-bar-medium-height': 22.0, 15 | 'progress-bar-large-height': 24.0, 16 | 'progress-bar-giant-height': 28.0, 17 | 'progress-bar-tiny-text-font-family': 'text-subtitle-2-font-family', 18 | 'progress-bar-tiny-text-font-weight': 'text-subtitle-2-font-weight', 19 | 'progress-bar-tiny-text-font-size': 'text-subtitle-2-font-size', 20 | 'progress-bar-small-text-font-family': 'text-subtitle-2-font-family', 21 | 'progress-bar-small-text-font-weight': 'text-subtitle-2-font-weight', 22 | 'progress-bar-small-text-font-size': 'text-subtitle-2-font-size', 23 | 'progress-bar-medium-text-font-family': 'text-subtitle-font-family', 24 | 'progress-bar-medium-text-font-weight': 'text-subtitle-font-weight', 25 | 'progress-bar-medium-text-font-size': 'text-subtitle-font-size', 26 | 'progress-bar-large-text-font-family': 'text-subtitle-font-family', 27 | 'progress-bar-large-text-font-weight': 'text-subtitle-font-weight', 28 | 'progress-bar-large-text-font-size': 'text-subtitle-font-size', 29 | 'progress-bar-giant-text-font-family': 'text-subtitle-font-family', 30 | 'progress-bar-giant-text-font-weight': 'text-subtitle-font-weight', 31 | 'progress-bar-giant-text-font-size': 'text-subtitle-font-size', 32 | 'progress-bar-background-color': 'background-basic-color-3', 33 | 'progress-bar-progress-color': 'color-primary-default', 34 | 'progress-bar-text-color': 'text-control-color', 35 | }) 36 | ..inject(_generateForStyle('primary')) 37 | ..inject(_generateForStyle('success')) 38 | ..inject(_generateForStyle('warning')) 39 | ..inject(_generateForStyle('danger')) 40 | ..inject(_generateForStyle('info')); 41 | -------------------------------------------------------------------------------- /equinox_visualqa/lib/theme.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | 3 | class Theme { 4 | static Map json = { 5 | "color-primary-100": "#DDFDF1", 6 | "color-primary-200": "#BCFCEA", 7 | "color-primary-300": "#98F6E4", 8 | "color-primary-400": "#7CEDE2", 9 | "color-primary-500": "#53E2E0", 10 | "color-primary-600": "#3CB8C2", 11 | "color-primary-700": "#298FA2", 12 | "color-primary-800": "#1A6983", 13 | "color-primary-900": "#0F4D6C", 14 | "color-success-100": "#E1FCD9", 15 | "color-success-200": "#BFF9B5", 16 | "color-success-300": "#91ED8C", 17 | "color-success-400": "#6BDC70", 18 | "color-success-500": "#3FC651", 19 | "color-success-600": "#2EAA4A", 20 | "color-success-700": "#1F8E43", 21 | "color-success-800": "#14723B", 22 | "color-success-900": "#0C5F35", 23 | "color-info-100": "#D4EBFF", 24 | "color-info-200": "#AAD4FF", 25 | "color-info-300": "#7FBAFF", 26 | "color-info-400": "#60A2FF", 27 | "color-info-500": "#2B7CFF", 28 | "color-info-600": "#1F5FDB", 29 | "color-info-700": "#1546B7", 30 | "color-info-800": "#0D3193", 31 | "color-info-900": "#08227A", 32 | "color-warning-100": "#FEFCCE", 33 | "color-warning-200": "#FDFA9E", 34 | "color-warning-300": "#FBF56E", 35 | "color-warning-400": "#F7EE4A", 36 | "color-warning-500": "#F2E610", 37 | "color-warning-600": "#D0C40B", 38 | "color-warning-700": "#AEA308", 39 | "color-warning-800": "#8C8205", 40 | "color-warning-900": "#746B03", 41 | "color-danger-100": "#FFE5D8", 42 | "color-danger-200": "#FFC5B1", 43 | "color-danger-300": "#FF9E8A", 44 | "color-danger-400": "#FF7A6D", 45 | "color-danger-500": "#FF3D3D", 46 | "color-danger-600": "#DB2C3B", 47 | "color-danger-700": "#B71E39", 48 | "color-danger-800": "#931334", 49 | "color-danger-900": "#7A0B32" 50 | }; 51 | 52 | static StyleData get lightTheme { 53 | return EqThemes.defaultLightTheme; 54 | //return EqThemes.defaultLightTheme; 55 | } 56 | 57 | static StyleData get darkTheme { 58 | return EqThemes.defaultDarkTheme; 59 | //return EqThemes.defaultDarkTheme; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /lib/equinox.dart: -------------------------------------------------------------------------------- 1 | // Global 2 | export 'package:equinox/src/components/global/theme.dart'; 3 | export 'package:equinox/src/components/global/layout.dart'; 4 | export 'package:equinox/src/components/global/outlined_widget.dart'; 5 | export 'package:equinox/src/components/global/outlined_gesture_detector.dart'; 6 | 7 | export 'package:equinox/src/components/global/app/equinox_app.dart'; 8 | export 'package:equinox/src/components/global/app/equinox_toast_service.dart'; 9 | export 'package:equinox/src/components/global/app/equinox_dialog_service.dart'; 10 | 11 | // Model 12 | export 'package:equinox/src/model/colors.dart'; 13 | export 'package:equinox/src/model/color_group.dart'; 14 | export 'package:equinox/src/model/params.dart'; 15 | export 'package:equinox/src/model/status.dart'; 16 | 17 | // Theme 18 | export 'package:equinox/src/theme/themes.dart'; 19 | export 'package:stylist/stylist.dart'; 20 | 21 | // Components 22 | export 'package:equinox/src/components/app_bar/app_bar.dart'; 23 | export 'package:equinox/src/components/button/button.dart'; 24 | //export 'package:equinox/src/components/calendar/calendar.dart'; 25 | export 'package:equinox/src/components/card/card.dart'; 26 | export 'package:equinox/src/components/checkbox/checkbox.dart'; 27 | export 'package:equinox/src/components/dialog/dialog.dart'; 28 | export 'package:equinox/src/components/divider/divider.dart'; 29 | export 'package:equinox/src/components/icon_button/icon_button.dart'; 30 | export 'package:equinox/src/components/list_item/list_item.dart'; 31 | export 'package:equinox/src/components/progress_bar/progress_bar.dart'; 32 | export 'package:equinox/src/components/radio/radio.dart'; 33 | export 'package:equinox/src/components/icon/icon.dart'; 34 | export 'package:equinox/src/components/select/select.dart'; 35 | export 'package:equinox/src/components/spinner/spinner.dart'; 36 | export 'package:equinox/src/components/tab_bar/tab_bar.dart'; 37 | export 'package:equinox/src/components/tabs/tabs.dart'; 38 | export 'package:equinox/src/components/text/text.dart'; 39 | export 'package:equinox/src/components/text_field/text_field.dart'; 40 | export 'package:equinox/src/components/text_field_form/text_field_form.dart'; 41 | export 'package:equinox/src/components/toast/toast.dart'; 42 | export 'package:equinox/src/components/toggle/toggle.dart'; 43 | 44 | // Icons 45 | export 'package:eva_icons_flutter/eva_icons_flutter.dart'; 46 | -------------------------------------------------------------------------------- /lib/src/components/toggle/toggle_style.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | 3 | StyleData _getForStatus(String status) { 4 | return StyleData({ 5 | 'toggle-$status-background-color': (style) => 6 | style.get('color-$status-default').withOpacity(0.125), 7 | 'toggle-$status-knob-color': 'text-control-color', 8 | 'toggle-$status-border-color': 'color-$status-default', 9 | 'toggle-$status-checked-background-color': 'color-$status-default', 10 | 'toggle-$status-checked-border-color': 'color-$status-default', 11 | 'toggle-$status-checked-knob-color': 'text-control-color', 12 | 'toggle-$status-focus-background-color': 'color-$status-hover', 13 | 'toggle-$status-focus-border-color': 'color-$status-hover', 14 | 'toggle-$status-focus-knob-color': 'text-control-color', 15 | }); 16 | } 17 | 18 | final StyleData toggleStyle = StyleData({ 19 | 'toggle-width': 52.0, 20 | 'toggle-height': 32.0, 21 | 'toggle-padding': 'control-padding', 22 | 'toggle-description-padding': 'control-description-padding', 23 | 'toggle-border-width': 'border-width', 24 | 'toggle-outline-width': 'outline-width', 25 | 'toggle-outline-color': 'outline-color', 26 | 'toggle-text-color': 'text-basic-color', 27 | 'toggle-text-font-family': 'text-subtitle-2-font-family', 28 | 'toggle-text-font-size': 'text-subtitle-2-font-size', 29 | 'toggle-text-font-weight': 'text-subtitle-2-font-weight', 30 | 'toggle-background-color': 'background-basic-color-3', 31 | 'toggle-border-color': 'border-basic-color-4', 32 | 'toggle-knob-color': 'text-control-color', 33 | 'toggle-disabled-background-color': 'background-basic-color-2', 34 | 'toggle-disabled-border-color': 'border-basic-color-3', 35 | 'toggle-disabled-knob-color': 'text-disabled-color', 36 | 'toggle-disabled-text-color': 'text-disabled-color', 37 | 'toggle-checked-background-color': 'color-primary-default', 38 | 'toggle-checked-border-color': 'color-primary-default', 39 | 'toggle-checked-knob-color': 'text-control-color', 40 | 'toggle-focus-background-color': 'color-primary-hover', 41 | 'toggle-focus-border-color': 'color-primary-hover', 42 | 'toggle-focus-knob-color': 'text-control-color', 43 | }) 44 | ..inject(_getForStatus('primary')) 45 | ..inject(_getForStatus('success')) 46 | ..inject(_getForStatus('warning')) 47 | ..inject(_getForStatus('danger')) 48 | ..inject(_getForStatus('info')); 49 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /equinox_visualqa/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 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 0.3.3 2 | 3 | - Minor AppBar sizing fix 4 | 5 | # 0.3.2 6 | 7 | - Fixed issue #8 8 | 9 | # 0.3.1 10 | 11 | - Breaking changes: 12 | - Added `leading`, `trailing`, `padding`, and other stuff into `EqButton`. 13 | - Added more customization for EqTabs. 14 | - Changed `EqTabData`. 15 | - Added `EqTabData.fromIcon()`. 16 | - Couple more bugfixes. 17 | 18 | # 0.2.4 19 | 20 | - Another `EqButton` hotfix. 21 | 22 | # 0.2.3 23 | 24 | - Fixed a bug in `EqButton`. 25 | 26 | # 0.2.2 27 | 28 | - Added `foregroundColor` and `backgroundColor` to `EqButton`. 29 | - Added `iconSize` to `EqTab`. 30 | 31 | # 0.2.1 32 | 33 | - A huge theming update - everything is written from scratch, now uses `stylist` to theme the app. 34 | 35 | # 0.1.4 36 | 37 | - Calendar updates, now production-ready. 38 | 39 | # 0.1.3 40 | 41 | - Added new widget - `EqTabBar`, a wrapper for `EqTabs`. Has two constructors, 42 | `EqTabBar.top()` and `EqTabBar.bottom()` to use as top tab bar and bottom tab bar. 43 | - Added slot for bottom tab bar in `EqLayout`. 44 | 45 | # 0.1.2 46 | 47 | - Added support for global widgets theming. 48 | - Added public API documentation. 49 | 50 | # 0.1.1 51 | 52 | - Breaking changes: `Themes` has been renamed to `EqThemes`. 53 | - Added methods for custom theming: `EqThemeData.loadFromAsset`, `EqThemeData.loadFromJson`. You can use these methods with [Eva Color Generator](https://colors.eva.design). 54 | - Will start working on documenting public API. 55 | 56 | # 0.0.13 57 | 58 | - Fixed #7 (AppBar unused space). 59 | - Added calendar (unfinished). 60 | 61 | # 0.0.12 62 | 63 | - Added `EqText`. 64 | 65 | # 0.0.11 66 | 67 | - Added `EqProgressBar`. 68 | 69 | # 0.0.10 70 | 71 | - Added `EqAppBar.withoutTitle()` method to fix #6. 72 | 73 | # 0.0.9 74 | 75 | - Added `EqDialogService` and dialogs. 76 | 77 | # 0.0.8 78 | 79 | - Added `EqToastService` and toasts. 80 | - Couple of bugfixes 81 | 82 | # 0.0.7 83 | 84 | - A ton of bugfixes 85 | - Added Showcase app (equinox_visualqa) 86 | 87 | # 0.0.6 88 | 89 | - Fixed bug #4 90 | - Fixed issues with `OutlinedWidget` 91 | - Fixed issues with outline and `EqIconButton` 92 | 93 | # 0.0.5 94 | 95 | - Added EqSpinner widget 96 | 97 | # 0.0.4 98 | 99 | - Fixed few bugs in OutlinedWidget, updated screenshots 100 | 101 | # 0.0.3 102 | 103 | - Fixed few critical bugs #2 and #3, added example 104 | 105 | # 0.0.2 106 | 107 | - Changed README, formatted files. 108 | 109 | # 0.0.1 110 | 111 | - Initial release -------------------------------------------------------------------------------- /lib/src/components/global/layout.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | import 'package:flutter/widgets.dart'; 3 | 4 | import 'package:flutter/material.dart' as MaterialDesign; 5 | 6 | /// A widget that represents a page. Similar to [Scaffold]. 7 | class EqLayout extends StatefulWidget { 8 | /// A theme to use in this page. Overwrites the [EquinoxApp.theme]. 9 | final StyleData theme; 10 | 11 | /// Page's body. Will be placed below [appBar]. 12 | final Widget child; 13 | 14 | /// A slot for [EqAppBar] or other application bars. Can be `null`. 15 | final PreferredSizeWidget appBar; 16 | 17 | /// A slot for [EqTabBar.bottom()] or other widget to place on the bottom. Can be `null`. 18 | final PreferredSizeWidget bottomTabBar; 19 | 20 | const EqLayout({ 21 | Key key, 22 | this.theme, 23 | @required this.child, 24 | this.appBar, 25 | this.bottomTabBar, 26 | }) : super(key: key); 27 | @override 28 | _EqLayoutState createState() => _EqLayoutState(); 29 | } 30 | 31 | class _EqLayoutState extends State { 32 | @override 33 | Widget build(BuildContext context) { 34 | final theme = widget.theme ?? StaticStyle.of(context)?.style; 35 | final topPadding = MediaQuery.of(context).padding.top; 36 | print(topPadding); 37 | print('ayy lmao'); 38 | return EqTheme( 39 | theme: theme, 40 | child: AnimatedContainer( 41 | duration: theme.get('major-animation-duration'), 42 | curve: theme.get('major-animation-curve'), 43 | color: theme.get('background-basic-color-3'), 44 | child: MaterialDesign.Material( 45 | type: MaterialDesign.MaterialType.transparency, 46 | child: Stack( 47 | children: [ 48 | Positioned( 49 | top: (widget.appBar != null) 50 | ? widget.appBar.preferredSize.height + 51 | MediaQuery.of(context).padding.top 52 | : 0.0, 53 | bottom: (widget.bottomTabBar != null) 54 | ? widget.bottomTabBar.preferredSize.height 55 | : 0.0, 56 | left: 0.0, 57 | right: 0.0, 58 | child: widget.child, 59 | ), 60 | if (widget.appBar != null) widget.appBar, 61 | if (widget.bottomTabBar != null) 62 | Align( 63 | alignment: Alignment.bottomCenter, 64 | child: widget.bottomTabBar, 65 | ), 66 | ], 67 | ), 68 | ), 69 | ), 70 | ); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /lib/src/components/select/select_overlay.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:equinox/equinox.dart'; 4 | import 'package:flutter/widgets.dart'; 5 | 6 | class EqSelectOverlay extends StatelessWidget { 7 | final EqWidgetStatus status; 8 | final Animation animation; 9 | final double borderRadius; 10 | final List items; 11 | final int selectedIndex; 12 | final void Function(int, EqSelectItem) onSelect; 13 | final bool openingFromBottom; 14 | final double height; 15 | 16 | const EqSelectOverlay({ 17 | Key key, 18 | this.animation, 19 | this.borderRadius, 20 | this.items, 21 | this.selectedIndex, 22 | this.onSelect, 23 | this.status, 24 | this.openingFromBottom, 25 | this.height, 26 | }) : super(key: key); 27 | 28 | @override 29 | Widget build(BuildContext context) { 30 | final style = StaticStyle.of(context); 31 | final maxBorderRadius = style.get('border-radius-semi-round'); 32 | final borderRadiusValue = min(borderRadius, maxBorderRadius); 33 | return AnimatedBuilder( 34 | animation: animation, 35 | builder: (ctx, child) => Container( 36 | constraints: BoxConstraints(maxHeight: height), 37 | child: EqCard( 38 | borderRadius: (openingFromBottom) 39 | ? BorderRadius.vertical( 40 | top: Radius.zero, 41 | bottom: Radius.circular(borderRadiusValue), 42 | ) 43 | : BorderRadius.vertical( 44 | top: Radius.circular(borderRadiusValue), 45 | bottom: Radius.zero, 46 | ), 47 | padding: EdgeInsets.zero, 48 | child: SizeTransition( 49 | axis: Axis.vertical, 50 | sizeFactor: animation, 51 | child: SizedBox( 52 | height: height, 53 | child: ListView( 54 | padding: EdgeInsets.zero, 55 | shrinkWrap: true, 56 | children: items.map((item) { 57 | int index = items.indexOf(item); 58 | return EqListItem( 59 | title: item.title, 60 | subtitle: item.subtitle, 61 | padding: EdgeInsets.all(16.0), 62 | icon: item.icon, 63 | onTap: () => onSelect(index, item), 64 | status: status, 65 | active: index == selectedIndex, 66 | ); 67 | }).toList(), 68 | ), 69 | ), 70 | ), 71 | ), 72 | ), 73 | ); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /lib/src/components/spinner/spinner.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | import 'package:equinox/equinox.dart'; 3 | import 'package:equinox/src/equinox_internal.dart'; 4 | export 'package:equinox/src/components/spinner/spinner_style.dart'; 5 | import 'package:flutter/widgets.dart'; 6 | import 'package:equinox/src/components/spinner/spinner_painter.dart'; 7 | 8 | /// Spinners are used to show user that something is downloading or in progress. 9 | /// To customize a spinner globally, you can use [EqThemeData.defaultSpinnerTheme] and 10 | /// [EqSpinnerThemeData]. 11 | class EqSpinner extends StatefulWidget { 12 | /// Status of a spinner. Controls its color. 13 | final EqWidgetStatus status; 14 | 15 | /// Size of a spinner. 16 | final EqWidgetSize size; 17 | 18 | const EqSpinner({ 19 | Key key, 20 | this.status = EqWidgetStatus.primary, 21 | this.size = EqWidgetSize.medium, 22 | }) : super(key: key); 23 | @override 24 | _EqSpinnerState createState() => _EqSpinnerState(); 25 | } 26 | 27 | class _EqSpinnerState extends State 28 | with SingleTickerProviderStateMixin { 29 | AnimationController animationController; 30 | Animation animation; 31 | 32 | initState() { 33 | super.initState(); 34 | animationController = 35 | AnimationController(vsync: this, duration: Duration(milliseconds: 800)); 36 | 37 | animation = CurvedAnimation( 38 | curve: Cubic(0.275, 0.725, 0.725, 0.275), parent: animationController); 39 | 40 | animationController.repeat(min: 0.0, max: 1.0); 41 | } 42 | 43 | dispose() { 44 | animationController.stop(); 45 | animationController.dispose(); 46 | super.dispose(); 47 | } 48 | 49 | @override 50 | Widget build(BuildContext context) { 51 | final style = StaticStyle.of(context); 52 | final size = style.get(generateSelector(['spinner', widget.size, 'size'])); 53 | return Center( 54 | widthFactor: 1.0, 55 | heightFactor: 1.0, 56 | child: AnimatedBuilder( 57 | animation: animation, 58 | builder: (context, _) { 59 | return Transform.rotate( 60 | angle: animation.value * pi * 2.0, 61 | child: CustomPaint( 62 | painter: SpinnerPainter( 63 | color: style 64 | .get(generateSelector(['spinner', widget.status, 'color'])), 65 | strokeWidth: style.get( 66 | generateSelector(['spinner', widget.size, 'stroke-width'])), 67 | ), 68 | isComplex: false, 69 | willChange: false, 70 | child: SizedBox(width: size, height: size), 71 | ), 72 | ); 73 | }, 74 | ), 75 | ); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /lib/src/components/radio/radio_style.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | 3 | StyleData _getStyle(String status) { 4 | return StyleData({ 5 | 'radio-$status-border-color': 'color-$status-default', 6 | 'radio-$status-background-color': (StyleData style) => 7 | style.get('color-$status-default').withOpacity(0.125), 8 | 'radio-$status-knob-color': Colors.transparent, 9 | 'radio-$status-focus-border-color': 'color-$status-hover', 10 | 'radio-$status-focus-background-color': (StyleData style) => 11 | style.get('color-$status-focus').withOpacity(0.125), 12 | 'radio-$status-focus-knob-color': 'color-$status-hover', 13 | 'radio-$status-selected-border-color': 'color-$status-default', 14 | 'radio-$status-selected-background-color': (StyleData style) => 15 | style.get('color-$status-default').withOpacity(0.125), 16 | 'radio-$status-selected-knob-color': 'color-$status-default', 17 | }); 18 | } 19 | 20 | final StyleData radioStyle = StyleData({ 21 | 'radio-size': 'icon-size', 22 | 'radio-border-width': 'border-width', 23 | 'radio-text-color': 'text-basic-color', 24 | 'radio-text-font-family': 'text-subtitle-2-font-family', 25 | 'radio-text-font-size': 'text-subtitle-2-font-size', 26 | 'radio-text-font-weight': 'text-subtitle-2-font-weight', 27 | 'radio-padding': 'control-padding', 28 | 'radio-description-padding': 'control-description-padding', 29 | 'radio-description-position': EqPositioning.right, 30 | 'radio-outline-color': 'outline-color', 31 | 'radio-outline-width': 'outline-width', 32 | 'radio-background-color': 'background-basic-color-3', 33 | 'radio-border-color': 'border-basic-color-4', 34 | 'radio-knob-color': Colors.transparent, 35 | 'radio-focus-border-color': 'color-primary-focus', 36 | 'radio-focus-background-color': 'radio-background-color', 37 | 'radio-focus-knob-color': 'color-primary-focus', 38 | 'radio-selected-border-color': 'color-primary-default', 39 | 'radio-selected-background-color': 'radio-background-color', 40 | 'radio-selected-knob-color': 'color-primary-default', 41 | 'radio-disabled-text-color': 'text-disabled-color', 42 | 'radio-disabled-border-color': 'border-basic-color-3', 43 | 'radio-disabled-background-color': 'background-basic-color-2', 44 | 'radio-disabled-knob-color': Colors.transparent, 45 | 'radio-disabled-selected-border-color': 'border-basic-color-3', 46 | 'radio-disabled-selected-background-color': 'background-basic-color-2', 47 | 'radio-disabled-selected-knob-color': 'background-basic-color-4', 48 | }) 49 | ..inject(_getStyle('primary')) 50 | ..inject(_getStyle('success')) 51 | ..inject(_getStyle('warning')) 52 | ..inject(_getStyle('danger')) 53 | ..inject(_getStyle('info')); 54 | -------------------------------------------------------------------------------- /equinox_visualqa/lib/management/interactive_playground.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | import 'package:equinox_visualqa/utils.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | class BoolTyped { 6 | bool value; 7 | 8 | BoolTyped(this.value); 9 | } 10 | 11 | class EnumTyped { 12 | T value; 13 | List values; 14 | 15 | EnumTyped(this.value, this.values); 16 | } 17 | 18 | class InteractivePlayground extends StatefulWidget { 19 | final Widget Function(StyleData theme, Map data) builder; 20 | final Map data; 21 | 22 | const InteractivePlayground({Key key, this.builder, this.data}) 23 | : super(key: key); 24 | @override 25 | _InteractivePlaygroundState createState() => _InteractivePlaygroundState(); 26 | } 27 | 28 | class _InteractivePlaygroundState extends State { 29 | Map dataCopy; 30 | 31 | @override 32 | void initState() { 33 | dataCopy = widget.data; 34 | super.initState(); 35 | } 36 | 37 | @override 38 | Widget build(BuildContext context) { 39 | final style = StaticStyle.of(context); 40 | var items = []; 41 | 42 | for (final String key in dataCopy.keys) { 43 | final dynamic data = dataCopy[key]; 44 | final String description = normalize(key); 45 | 46 | if (data is BoolTyped) { 47 | items.add( 48 | EqCheckbox( 49 | value: data.value, 50 | onChanged: (v) => setState(() => dataCopy[key].value = v), 51 | description: description, 52 | descriptionPosition: EqPositioning.right, 53 | ), 54 | ); 55 | } else if (data is EnumTyped) { 56 | items.add(EqSelect( 57 | hint: description, 58 | items: data.values 59 | .map( 60 | (value) => EqSelectItem( 61 | title: enumToString(value), 62 | value: value, 63 | ), 64 | ) 65 | .toList(), 66 | onSelect: (v) => setState(() => dataCopy[key].value = v), 67 | label: description, 68 | selectedIndex: data.values.indexOf(data.value), 69 | )); 70 | } 71 | items.add(SizedBox(height: 16.0)); 72 | } 73 | 74 | items.add( 75 | widget.builder( 76 | style.style, 77 | dataCopy.map( 78 | (k, v) => MapEntry(k, v.value), 79 | ), 80 | ), 81 | ); 82 | 83 | return EqCard( 84 | statusAppearance: EqCardStatusAppearance.none, 85 | header: Text('Interactive playground'), 86 | child: Column( 87 | crossAxisAlignment: CrossAxisAlignment.start, 88 | children: items, 89 | ), 90 | ); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /lib/src/components/checkbox/checkbox_style.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | 3 | StyleData _getForStatus(String status) { 4 | return StyleData({ 5 | 'checkbox-$status-background-color': (style) => 6 | style.get('color-$status-default').withOpacity(0.125), 7 | 'checkbox-$status-border-color': 'color-$status-default', 8 | 'checkbox-$status-checked-background-color': 'color-$status-default', 9 | 'checkbox-$status-checked-border-color': 'color-$status-default', 10 | 'checkbox-$status-checked-checkmark-color': 'text-control-color', 11 | 'checkbox-$status-indeterminate-background-color': 'color-$status-default', 12 | 'checkbox-$status-indeterminate-border-color': 'color-$status-default', 13 | 'checkbox-$status-indeterminate-checkmark-color': 'text-control-color', 14 | 'checkbox-$status-focus-background-color': 'color-$status-hover', 15 | 'checkbox-$status-focus-border-color': 'color-$status-hover', 16 | 'checkbox-$status-focus-checkmark-color': 'text-control-color', 17 | }); 18 | } 19 | 20 | final StyleData checkboxStyle = StyleData({ 21 | 'checkbox-size': 'icon-size', 22 | 'checkbox-padding': 'control-padding', 23 | 'checkbox-description-padding': 'control-description-padding', 24 | 'checkbox-background-color': 'background-basic-color-3', 25 | 'checkbox-border-color': 'border-basic-color-4', 26 | 'checkbox-border-width': 'border-width', 27 | 'checkbox-outline-width': 'outline-width', 28 | 'checkbox-outline-color': 'outline-color', 29 | 'checkbox-text-color': 'text-basic-color', 30 | 'checkbox-text-font-family': 'text-subtitle-2-font-family', 31 | 'checkbox-text-font-size': 'text-subtitle-2-font-size', 32 | 'checkbox-text-font-weight': 'text-subtitle-2-font-weight', 33 | 'checkbox-disabled-background-color': 'background-basic-color-2', 34 | 'checkbox-disabled-border-color': 'border-basic-color-3', 35 | 'checkbox-disabled-checkmark-color': 'text-disabled-color', 36 | 'checkbox-disabled-text-color': 'text-disabled-color', 37 | 'checkbox-checked-background-color': 'color-primary-default', 38 | 'checkbox-checked-border-color': 'color-primary-default', 39 | 'checkbox-checked-checkmark-color': 'text-control-color', 40 | 'checkbox-indeterminate-background-color': 'color-primary-default', 41 | 'checkbox-indeterminate-border-color': 'color-primary-default', 42 | 'checkbox-indeterminate-checkmark-color': 'text-control-color', 43 | 'checkbox-focus-background-color': 'color-primary-hover', 44 | 'checkbox-focus-border-color': 'color-primary-hover', 45 | 'checkbox-focus-checkmark-color': 'text-control-color', 46 | }) 47 | ..inject(_getForStatus('primary')) 48 | ..inject(_getForStatus('success')) 49 | ..inject(_getForStatus('warning')) 50 | ..inject(_getForStatus('danger')) 51 | ..inject(_getForStatus('info')); 52 | -------------------------------------------------------------------------------- /lib/src/components/tabs/tabs.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | import 'package:flutter/widgets.dart'; 3 | export 'package:equinox/src/components/tabs/tab.dart'; 4 | 5 | /// Tabs are generally put inside [EqAppBar.bottom]. It can be used to display various 6 | /// paths or pages. 7 | /// 8 | /// [tabs] must not be null. 9 | class EqTabs extends StatefulWidget implements PreferredSizeWidget { 10 | /// Index of a tab that is selected by default. 11 | final int defaultSelected; 12 | 13 | /// This method is called when a tab is selected. Can be `null` to make all tabs disabled. 14 | final Function(int) onSelect; 15 | 16 | /// List of all tabs. See [EqTabData] for more; 17 | final List tabs; 18 | 19 | /// Whether to show the pager indicator 20 | final bool showPagerIndicator; 21 | 22 | /// Position of the pager indicator (on top or on bottom) 23 | final EqVerticalPositioning pagerIndicatorPosition; 24 | 25 | const EqTabs({ 26 | Key key, 27 | this.defaultSelected, 28 | @required this.onSelect, 29 | @required this.tabs, 30 | this.showPagerIndicator = true, 31 | this.pagerIndicatorPosition = EqVerticalPositioning.bottom, 32 | }) : super(key: key); 33 | @override 34 | _EqTabsState createState() => _EqTabsState(); 35 | 36 | @override 37 | Size get preferredSize => Size.fromHeight(48.0); 38 | } 39 | 40 | class _EqTabsState extends State { 41 | int selected = 0; 42 | 43 | @override 44 | void initState() { 45 | if (widget.defaultSelected != null) selected = widget.defaultSelected; 46 | super.initState(); 47 | } 48 | 49 | void onSelect(int index) { 50 | selected = index; 51 | widget.onSelect(index); 52 | setState(() {}); 53 | } 54 | 55 | @override 56 | Widget build(BuildContext context) { 57 | var tabs = []; 58 | for (int i = 0; i < widget.tabs.length; i++) { 59 | final tab = widget.tabs[i]; 60 | tabs.add( 61 | Flexible( 62 | flex: 1, 63 | child: EqTab( 64 | pagerIndicatorAlignment: 65 | (widget.pagerIndicatorPosition == EqVerticalPositioning.top) 66 | ? Alignment.topCenter 67 | : Alignment.bottomCenter, 68 | showPagerIndicator: widget.showPagerIndicator, 69 | data: tab, 70 | active: selected == i, 71 | onTap: (tab.disabled || widget.onSelect == null) 72 | ? null 73 | : () => onSelect(i), 74 | ), 75 | ), 76 | ); 77 | if (i != widget.tabs.length - 1) tabs.add(SizedBox(width: 4.0)); 78 | } 79 | return Container( 80 | height: 48.0, 81 | child: Row( 82 | mainAxisSize: MainAxisSize.max, 83 | children: tabs, 84 | ), 85 | ); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: example 2 | description: A new Flutter project. 3 | 4 | # The following defines the version and build number for your application. 5 | # A version number is three numbers separated by dots, like 1.2.43 6 | # followed by an optional build number separated by a +. 7 | # Both the version and the builder number may be overridden in flutter 8 | # build by specifying --build-name and --build-number, respectively. 9 | # In Android, build-name is used as versionName while build-number used as versionCode. 10 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 11 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. 12 | # Read more about iOS versioning at 13 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 14 | version: 1.0.0+1 15 | 16 | environment: 17 | sdk: ">=2.1.0 <3.0.0" 18 | 19 | dependencies: 20 | flutter: 21 | sdk: flutter 22 | 23 | equinox: 24 | path: ../ 25 | 26 | dev_dependencies: 27 | flutter_test: 28 | sdk: flutter 29 | 30 | 31 | # For information on the generic Dart part of this file, see the 32 | # following page: https://www.dartlang.org/tools/pub/pubspec 33 | 34 | # The following section is specific to Flutter. 35 | flutter: 36 | 37 | # The following line ensures that the Material Icons font is 38 | # included with your application, so that you can use the icons in 39 | # the material Icons class. 40 | uses-material-design: true 41 | 42 | # To add assets to your application, add an assets section, like this: 43 | # assets: 44 | # - images/a_dot_burr.jpeg 45 | # - images/a_dot_ham.jpeg 46 | 47 | # An image asset can refer to one or more resolution-specific "variants", see 48 | # https://flutter.dev/assets-and-images/#resolution-aware. 49 | 50 | # For details regarding adding assets from package dependencies, see 51 | # https://flutter.dev/assets-and-images/#from-packages 52 | 53 | # To add custom fonts to your application, add a fonts section here, 54 | # in this "flutter" section. Each entry in this list should have a 55 | # "family" key with the font family name, and a "fonts" key with a 56 | # list giving the asset and other descriptors for the font. For 57 | # example: 58 | # fonts: 59 | # - family: Schyler 60 | # fonts: 61 | # - asset: fonts/Schyler-Regular.ttf 62 | # - asset: fonts/Schyler-Italic.ttf 63 | # style: italic 64 | # - family: Trajan Pro 65 | # fonts: 66 | # - asset: fonts/TrajanPro.ttf 67 | # - asset: fonts/TrajanPro_Bold.ttf 68 | # weight: 700 69 | # 70 | # For details regarding fonts from package dependencies, 71 | # see https://flutter.dev/custom-fonts/#from-packages 72 | -------------------------------------------------------------------------------- /lib/src/model/params.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | import 'package:flutter/widgets.dart'; 3 | 4 | enum EqWidgetSize { 5 | giant, 6 | large, 7 | medium, 8 | small, 9 | tiny, 10 | } 11 | 12 | enum EqWidgetState { 13 | normal, 14 | hover, 15 | active, 16 | focus, 17 | disabled, 18 | } 19 | 20 | enum EqWidgetStatus { 21 | primary, 22 | success, 23 | info, 24 | warning, 25 | danger, 26 | } 27 | 28 | enum EqWidgetShape { 29 | rectangle, 30 | round, 31 | semiRound, 32 | } 33 | 34 | enum EqWidgetAppearance { 35 | filled, 36 | outline, 37 | ghost, 38 | } 39 | 40 | enum EqPositioning { 41 | left, 42 | right, 43 | none, 44 | } 45 | 46 | enum EqVerticalPositioning { 47 | top, 48 | bottom, 49 | } 50 | 51 | String enumValueToString(dynamic e) { 52 | String str = e.toString(); 53 | return str.split('.').last; 54 | } 55 | 56 | class EqWidgetShapeUtils { 57 | static Radius getRadius({StyleData style, EqWidgetShape shape}) { 58 | final widgetShape = shape ?? style.get('widget-shape'); 59 | 60 | switch (widgetShape) { 61 | case EqWidgetShape.rectangle: 62 | return Radius.circular(style.get('border-radius-rectangle')); 63 | case EqWidgetShape.round: 64 | return Radius.circular(1000.0); // Fix this... 65 | case EqWidgetShape.semiRound: 66 | return Radius.circular(style.get('border-radius-semi-round')); 67 | default: 68 | return Radius.circular(style.get('border-radius-rectangle')); 69 | } 70 | } 71 | } 72 | /* 73 | class WidgetSizeUtils { 74 | static double getSizeValue({WidgetSize size}) { 75 | switch (size) { 76 | case WidgetSize.giant: 77 | return 56.0; 78 | case WidgetSize.large: 79 | return 48.0; 80 | case WidgetSize.medium: 81 | return 40.0; 82 | case WidgetSize.small: 83 | return 32.0; 84 | case WidgetSize.tiny: 85 | return 24.0; 86 | default: 87 | return 40.0; 88 | } 89 | } 90 | 91 | static EdgeInsets getPadding({WidgetSize size}) { 92 | switch (size) { 93 | case WidgetSize.giant: 94 | return EdgeInsets.symmetric(vertical: 16.0, horizontal: 26.0); 95 | case WidgetSize.large: 96 | return EdgeInsets.symmetric(vertical: 14.0, horizontal: 22.0); 97 | case WidgetSize.medium: 98 | return EdgeInsets.symmetric(vertical: 12.0, horizontal: 18.0); 99 | case WidgetSize.small: 100 | return EdgeInsets.symmetric(vertical: 10.0, horizontal: 18.0); 101 | case WidgetSize.tiny: 102 | return EdgeInsets.symmetric(vertical: 6.0, horizontal: 14.0); 103 | default: 104 | return EdgeInsets.symmetric(vertical: 10.0, horizontal: 18.0); 105 | } 106 | } 107 | }} 108 | */ 109 | -------------------------------------------------------------------------------- /equinox_visualqa/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: equinox_visualqa 2 | description: A new Flutter project. 3 | 4 | # The following defines the version and build number for your application. 5 | # A version number is three numbers separated by dots, like 1.2.43 6 | # followed by an optional build number separated by a +. 7 | # Both the version and the builder number may be overridden in flutter 8 | # build by specifying --build-name and --build-number, respectively. 9 | # In Android, build-name is used as versionName while build-number used as versionCode. 10 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 11 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. 12 | # Read more about iOS versioning at 13 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 14 | version: 1.0.0+1 15 | 16 | environment: 17 | sdk: ">=2.2.2 <3.0.0" 18 | 19 | dependencies: 20 | flutter: 21 | sdk: flutter 22 | 23 | equinox: 24 | path: ../ 25 | 26 | separated_column: 27 | 28 | dev_dependencies: 29 | flutter_test: 30 | sdk: flutter 31 | 32 | 33 | # For information on the generic Dart part of this file, see the 34 | # following page: https://www.dartlang.org/tools/pub/pubspec 35 | 36 | # The following section is specific to Flutter. 37 | flutter: 38 | 39 | # The following line ensures that the Material Icons font is 40 | # included with your application, so that you can use the icons in 41 | # the material Icons class. 42 | uses-material-design: true 43 | 44 | # To add assets to your application, add an assets section, like this: 45 | # assets: 46 | # - images/a_dot_burr.jpeg 47 | # - images/a_dot_ham.jpeg 48 | 49 | # An image asset can refer to one or more resolution-specific "variants", see 50 | # https://flutter.dev/assets-and-images/#resolution-aware. 51 | 52 | # For details regarding adding assets from package dependencies, see 53 | # https://flutter.dev/assets-and-images/#from-packages 54 | 55 | # To add custom fonts to your application, add a fonts section here, 56 | # in this "flutter" section. Each entry in this list should have a 57 | # "family" key with the font family name, and a "fonts" key with a 58 | # list giving the asset and other descriptors for the font. For 59 | # example: 60 | # fonts: 61 | # - family: Schyler 62 | # fonts: 63 | # - asset: fonts/Schyler-Regular.ttf 64 | # - asset: fonts/Schyler-Italic.ttf 65 | # style: italic 66 | # - family: Trajan Pro 67 | # fonts: 68 | # - asset: fonts/TrajanPro.ttf 69 | # - asset: fonts/TrajanPro_Bold.ttf 70 | # weight: 700 71 | # 72 | # For details regarding fonts from package dependencies, 73 | # see https://flutter.dev/custom-fonts/#from-packages 74 | -------------------------------------------------------------------------------- /lib/src/components/dialog/dialog.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | import 'package:flutter/widgets.dart'; 3 | 4 | /// Dialogs are used to show modal content for user to take action on. 5 | class EqDialog extends StatelessWidget { 6 | /// A widget to use as dialog's body. Gets padded by [padding]. 7 | final Widget child; 8 | 9 | /// A widget to use as dialog's header. Gets padded by [headerPadding] or [padding]. 10 | /// Set [headerPadding] to `EdgeInsets.zero` if you want no padding. 11 | final Widget header; 12 | 13 | /// A widget to use as dialog's header. Gets padded by [footerPadding] or [padding]. 14 | /// Set [footerPadding] to `EdgeInsets.zero` if you want no padding. 15 | final Widget footer; 16 | 17 | /// A dialog's status. It will be dispalyed according to [statusAppearance]. 18 | /// - If [statusAppearance] is [CardStatusAppearance.header], only the header will be painted in 19 | /// the status's color. 20 | /// - If [statusAppearance] is [CardStatusAppearance.strip], the status will be displayed as 21 | /// tiny line on top of the dialog. 22 | /// - Otherwise, no status will be displayed. 23 | final EqWidgetStatus status; 24 | 25 | /// Controls the dialog's border radius. If none is passed, uses [EqThemeData.defaultWidgetShape]. 26 | final EqWidgetShape shape; 27 | 28 | /// Controls the dialog's status appearance. See [status] for more details. 29 | final EqCardStatusAppearance statusAppearance; 30 | 31 | /// Controls the padding of the child. Also sets the [headerPadding] and [footerPadding] if they're null. 32 | final EdgeInsets padding; 33 | 34 | /// Controls the padding for the header. Gets set by [padding] if it's `null`. See [header]. 35 | final EdgeInsets headerPadding; 36 | 37 | /// Controls the padding for the footer. Gets set by [padding] if it's `null`. See [footer]. 38 | final EdgeInsets footerPadding; 39 | 40 | const EqDialog({ 41 | Key key, 42 | this.header, 43 | this.footer, 44 | this.headerPadding, 45 | this.footerPadding, 46 | this.padding = const EdgeInsets.all(16.0), 47 | this.status = EqWidgetStatus.primary, 48 | this.shape = EqWidgetShape.rectangle, 49 | this.statusAppearance = EqCardStatusAppearance.header, 50 | @required this.child, 51 | }) : super(key: key); 52 | 53 | @override 54 | Widget build(BuildContext context) { 55 | final size = MediaQuery.of(context).size; 56 | return Container( 57 | constraints: BoxConstraints( 58 | minWidth: size.width * 0.6, maxWidth: size.width * 0.9), 59 | padding: const EdgeInsets.all(16.0), 60 | child: EqCard( 61 | header: header, 62 | child: child, 63 | footer: footer, 64 | footerPadding: footerPadding, 65 | headerPadding: headerPadding, 66 | padding: padding, 67 | shape: shape, 68 | status: status, 69 | statusAppearance: statusAppearance, 70 | ), 71 | ); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # equinox 2 | [Eva Design System](https://eva.design) 3 | [![Pub](https://img.shields.io/pub/vpre/equinox.svg)](https://pub.dev/packages/equinox) 4 | 5 | 6 | A [**Eva Design**](https://eva.design) implementation in Flutter. 7 | 8 | ## Screenshots 9 | 10 |

11 | 12 | 13 | 14 | 15 |

16 | 17 | ## Tutorials and documentation 18 | 19 | You can check out the documentation in [**here**](https://pub.dev/documentation/equinox/latest/), and wiki in [**here**](https://github.com/kekland/equinox/wiki). 20 | 21 | ## Getting started 22 | 23 | ### Depend on it 24 | 25 | Add this to your package's pubspec.yaml file: 26 | 27 | ```yaml 28 | dependencies: 29 | equinox: ^0.3.3 30 | ``` 31 | 32 | ### Install it 33 | 34 | You can install packages from the command line: 35 | 36 | ```bash 37 | $ flutter pub get 38 | ``` 39 | 40 | ### Import it 41 | 42 | Now in your Dart code, you can use: 43 | 44 | ```dart 45 | import 'package:equinox/equinox.dart'; 46 | ``` 47 | 48 | ### Setup 49 | 50 | You have to replace `MaterialApp` or `CupertinoApp` with `EquinoxApp`. 51 | 52 | ```dart 53 | class MyApp extends StatelessWidget { 54 | @override 55 | Widget build(BuildContext context) { 56 | return EquinoxApp( 57 | theme: EqThemes.defaultLightTheme, 58 | title: 'Flutter Demo', 59 | home: HomePage(), 60 | ); 61 | } 62 | } 63 | ``` 64 | 65 | Then, instead of a `Scaffold` you have to use `EqLayout`. 66 | 67 | ```dart 68 | @override 69 | Widget build(BuildContext context) { 70 | return EqLayout( 71 | appBar: EqAppBar( 72 | centerTitle: true, 73 | title: 'Auth test', 74 | subtitle: 'v0.0.3', 75 | ), 76 | child: MyBody(), 77 | ); 78 | } 79 | ``` 80 | 81 | ### Use it 82 | 83 | Every widget in **Equinox** is prefixed with `Eq`. For example, `EqButton`, `EqTabs`, etc. 84 | 85 | ```dart 86 | EqButton( 87 | appearance: WidgetAppearance.ghost, 88 | onTap: () {}, 89 | label: 'Log in', 90 | size: WidgetSize.large, 91 | status: WidgetStatus.primary, 92 | ), 93 | ``` 94 | 95 | ## Customization 96 | 97 | Customization is done using [stylist](https://github.com/kekland/stylist). I will write a guide on styling your app soon. 98 | 99 | ## Other Eva Design implementations 100 | 101 | - [**Angular**](https://github.com/akveo/nebular) 102 | - [**React Native**](https://github.com/akveo/react-native-ui-kitten) 103 | 104 | ## Icons 105 | 106 | The [Eva Icons Flutter](https://github.com/piyushmaurya23/eva_icons_flutter) package is already integrated into Equinox, so you can use it right away by using `EvaIcons`. 107 | 108 | ## Credits 109 | 110 | - Eva Design Team: [Repository](https://github.com/eva-design/eva) 111 | 112 | ## Contact me 113 | 114 | **E-Mail**: `kk.erzhan@gmail.com` 115 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: equinox 2 | description: Flutter UI library based on Eva Design System - with every component you need for an app. 3 | author: kekland 4 | homepage: https://github.com/kekland/equinox 5 | 6 | # The following defines the version and build number for your application. 7 | # A version number is three numbers separated by dots, like 1.2.43 8 | # followed by an optional build number separated by a +. 9 | # Both the version and the builder number may be overridden in flutter 10 | # build by specifying --build-name and --build-number, respectively. 11 | # In Android, build-name is used as versionName while build-number used as versionCode. 12 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 13 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. 14 | # Read more about iOS versioning at 15 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 16 | version: 0.3.3 17 | 18 | environment: 19 | sdk: ">=2.2.2 <3.0.0" 20 | 21 | dependencies: 22 | flutter: 23 | sdk: flutter 24 | 25 | # The following adds the Cupertino Icons font to your application. 26 | # Use with the CupertinoIcons class for iOS style icons. 27 | eva_icons_flutter: ^2.0.0 28 | stylist: ^0.0.4 29 | vector_math: ^2.0.8 30 | 31 | dev_dependencies: 32 | flutter_test: 33 | sdk: flutter 34 | 35 | 36 | # For information on the generic Dart part of this file, see the 37 | # following page: https://dart.dev/tools/pub/pubspec 38 | 39 | # The following section is specific to Flutter. 40 | flutter: 41 | 42 | # The following line ensures that the Material Icons font is 43 | # included with your application, so that you can use the icons in 44 | # the material Icons class. 45 | uses-material-design: true 46 | 47 | # To add assets to your application, add an assets section, like this: 48 | # assets: 49 | # - images/a_dot_burr.jpeg 50 | # - images/a_dot_ham.jpeg 51 | 52 | # An image asset can refer to one or more resolution-specific "variants", see 53 | # https://flutter.dev/assets-and-images/#resolution-aware. 54 | 55 | # For details regarding adding assets from package dependencies, see 56 | # https://flutter.dev/assets-and-images/#from-packages 57 | 58 | # To add custom fonts to your application, add a fonts section here, 59 | # in this "flutter" section. Each entry in this list should have a 60 | # "family" key with the font family name, and a "fonts" key with a 61 | # list giving the asset and other descriptors for the font. For 62 | # example: 63 | # fonts: 64 | # - family: Schyler 65 | # fonts: 66 | # - asset: fonts/Schyler-Regular.ttf 67 | # - asset: fonts/Schyler-Italic.ttf 68 | # style: italic 69 | # - family: Trajan Pro 70 | # fonts: 71 | # - asset: fonts/TrajanPro.ttf 72 | # - asset: fonts/TrajanPro_Bold.ttf 73 | # weight: 700 74 | # 75 | # For details regarding fonts from package dependencies, 76 | # see https://flutter.dev/custom-fonts/#from-packages 77 | -------------------------------------------------------------------------------- /equinox_visualqa/lib/components/card.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:equinox_visualqa/management/showcase_state.dart'; 4 | 5 | String equinoxDescription = 6 | "An equinox is commonly regarded as the instant of time when the plane (extended indefinitely in all directions) of Earth's equator passes through the center of the Sun."; 7 | 8 | class CardShowcase extends StatefulWidget { 9 | @override 10 | _CardShowcaseState createState() => _CardShowcaseState(); 11 | } 12 | 13 | class _CardShowcaseState extends ShowcaseState { 14 | @override 15 | Widget playgroundBuilder() => SizedBox(); 16 | 17 | @override 18 | String get showcaseName => 'Cards'; 19 | 20 | @override 21 | List get showcases => [ 22 | ShowcaseWidgetData( 23 | builder: () => EqCard( 24 | statusAppearance: EqCardStatusAppearance.none, 25 | header: Text('Basic card'), 26 | child: Text(equinoxDescription), 27 | ), 28 | override: true, 29 | ), 30 | ShowcaseWidgetData( 31 | builder: () => EqCard( 32 | statusAppearance: EqCardStatusAppearance.none, 33 | header: Text('With header and footer'), 34 | child: Text(equinoxDescription), 35 | footer: Text('By Wikipedia'), 36 | ), 37 | override: true, 38 | ), 39 | ShowcaseWidgetData( 40 | builder: () => EqCard( 41 | status: EqWidgetStatus.success, 42 | statusAppearance: EqCardStatusAppearance.header, 43 | header: Text('With status'), 44 | child: Text(equinoxDescription), 45 | footer: Text('By Wikipedia'), 46 | ), 47 | override: true, 48 | ), 49 | ShowcaseWidgetData( 50 | builder: () => EqCard( 51 | status: EqWidgetStatus.warning, 52 | statusAppearance: EqCardStatusAppearance.strip, 53 | header: Text('With status as a tiny strip'), 54 | child: Text(equinoxDescription), 55 | footer: Text('By Wikipedia'), 56 | ), 57 | override: true, 58 | ), 59 | ShowcaseWidgetData( 60 | title: 'Card shapes', 61 | builder: () => Column( 62 | children: [ 63 | EqCard( 64 | status: EqWidgetStatus.success, 65 | statusAppearance: EqCardStatusAppearance.strip, 66 | header: Text('Rectangle'), 67 | child: Text(equinoxDescription), 68 | shape: EqWidgetShape.rectangle, 69 | footer: Text('By Wikipedia'), 70 | ), 71 | SizedBox(height: 16.0), 72 | EqCard( 73 | status: EqWidgetStatus.danger, 74 | shape: EqWidgetShape.semiRound, 75 | statusAppearance: EqCardStatusAppearance.strip, 76 | header: Text('Semi Round'), 77 | child: Text(equinoxDescription), 78 | footer: Text('By Wikipedia'), 79 | ), 80 | ], 81 | ), 82 | ), 83 | ]; 84 | } 85 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /equinox_visualqa/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 | -------------------------------------------------------------------------------- /equinox_visualqa/lib/components/toggle.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:equinox_visualqa/management/showcase_state.dart'; 4 | import 'package:equinox_visualqa/utils.dart'; 5 | import 'package:separated_column/separated_column.dart'; 6 | 7 | class ToggleShowcase extends StatefulWidget { 8 | @override 9 | _ToggleShowcaseState createState() => _ToggleShowcaseState(); 10 | } 11 | 12 | class _ToggleShowcaseState extends ShowcaseState { 13 | @override 14 | Widget playgroundBuilder() => SizedBox(); 15 | 16 | @override 17 | String get showcaseName => 'Toggles'; 18 | 19 | Map status = {}; 20 | 21 | bool getStatus(String key, [bool def = true]) { 22 | if (status.containsKey(key)) return status[key]; 23 | status[key] = def; 24 | return def; 25 | } 26 | 27 | setStatus(String key, bool value) { 28 | status[key] = value; 29 | setState(() {}); 30 | } 31 | 32 | @override 33 | List get showcases => [ 34 | ShowcaseWidgetData( 35 | title: 'Toggle', 36 | builder: () => SeparatedColumn( 37 | crossAxisAlignment: CrossAxisAlignment.start, 38 | children: [ 39 | EqToggle( 40 | value: getStatus('d.0', true), 41 | onChanged: (v) => setStatus('d.0', v), 42 | description: 'Description', 43 | ), 44 | EqToggle( 45 | value: false, 46 | onChanged: null, 47 | description: 'Disabled', 48 | ), 49 | EqToggle( 50 | value: true, 51 | onChanged: null, 52 | description: 'Selected disabled', 53 | ), 54 | ], 55 | separatorBuilder: (_, i) => SizedBox(height: 16.0), 56 | ), 57 | ), 58 | ShowcaseWidgetData( 59 | title: 'Toggle colors', 60 | builder: () => SeparatedColumn( 61 | crossAxisAlignment: CrossAxisAlignment.start, 62 | children: EqWidgetStatus.values 63 | .map( 64 | (value) => EqToggle( 65 | value: getStatus(value.toString(), false), 66 | onChanged: (v) => setStatus(value.toString(), v), 67 | description: enumToString(value), 68 | status: value, 69 | ), 70 | ) 71 | .toList(), 72 | separatorBuilder: (_, i) => SizedBox(height: 16.0), 73 | ), 74 | ), 75 | ShowcaseWidgetData( 76 | title: 'Description location', 77 | builder: () => SeparatedColumn( 78 | crossAxisAlignment: CrossAxisAlignment.start, 79 | children: EqPositioning.values 80 | .map( 81 | (value) => EqToggle( 82 | value: getStatus(value.toString(), false), 83 | onChanged: (v) => setStatus(value.toString(), v), 84 | description: enumToString(value), 85 | descriptionPosition: value, 86 | ), 87 | ) 88 | .toList(), 89 | separatorBuilder: (_, i) => SizedBox(height: 16.0), 90 | ), 91 | ), 92 | ]; 93 | } 94 | -------------------------------------------------------------------------------- /equinox_visualqa/lib/components/tabs.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:equinox_visualqa/management/showcase_state.dart'; 4 | 5 | class TabsShowcase extends StatefulWidget { 6 | @override 7 | _TabsShowcaseState createState() => _TabsShowcaseState(); 8 | } 9 | 10 | class _TabsShowcaseState extends ShowcaseState { 11 | @override 12 | Widget playgroundBuilder() => InteractivePlayground( 13 | data: { 14 | 'enabled': BoolTyped(true), 15 | 'hasIcons': BoolTyped(true), 16 | }, 17 | builder: (_, data) => EqTabBar.top( 18 | tabs: [ 19 | EqTabData.fromIcon( 20 | icon: data['hasIcons'] ? EvaIcons.star : null, title: 'Tab'), 21 | EqTabData.fromIcon( 22 | icon: data['hasIcons'] ? EvaIcons.star : null, title: 'Tab'), 23 | EqTabData.fromIcon( 24 | icon: data['hasIcons'] ? EvaIcons.star : null, title: 'Tab'), 25 | ], 26 | onSelect: data['enabled'] ? (i) {} : null, 27 | ), 28 | ); 29 | 30 | @override 31 | String get showcaseName => 'TabBar'; 32 | 33 | @override 34 | List get showcases => [ 35 | ShowcaseWidgetData( 36 | title: 'Tabs', 37 | builder: () => EqCard( 38 | padding: const EdgeInsets.all(4.0), 39 | child: EqTabBar.top( 40 | tabs: [ 41 | EqTabData.fromIcon(icon: EvaIcons.star, title: 'Tab'), 42 | EqTabData.fromIcon(icon: EvaIcons.star, title: 'Tab'), 43 | EqTabData.fromIcon(icon: EvaIcons.star, title: 'Tab'), 44 | ], 45 | onSelect: (_) {}, 46 | ), 47 | ), 48 | ), 49 | ShowcaseWidgetData( 50 | title: 'Tabs without icons', 51 | builder: () => EqCard( 52 | padding: const EdgeInsets.all(4.0), 53 | child: EqTabBar.top( 54 | tabs: [ 55 | EqTabData.fromIcon(title: 'Tab'), 56 | EqTabData.fromIcon(title: 'Tab'), 57 | EqTabData.fromIcon(title: 'Tab'), 58 | ], 59 | onSelect: (_) {}, 60 | ), 61 | ), 62 | ), 63 | ShowcaseWidgetData( 64 | title: 'Disabled tabs', 65 | builder: () => EqCard( 66 | padding: const EdgeInsets.all(4.0), 67 | child: EqTabBar.top( 68 | tabs: [ 69 | EqTabData.fromIcon(icon: EvaIcons.star, title: 'Tab'), 70 | EqTabData.fromIcon(icon: EvaIcons.star, title: 'Tab'), 71 | EqTabData.fromIcon(icon: EvaIcons.star, title: 'Tab'), 72 | ], 73 | onSelect: null, 74 | ), 75 | ), 76 | ), 77 | ShowcaseWidgetData( 78 | title: 'Partially disabled tabs', 79 | builder: () => EqCard( 80 | padding: const EdgeInsets.all(4.0), 81 | child: EqTabBar.top( 82 | tabs: [ 83 | EqTabData.fromIcon(icon: EvaIcons.star, title: 'Tab'), 84 | EqTabData.fromIcon( 85 | icon: EvaIcons.star, title: 'Tab', disabled: true), 86 | EqTabData.fromIcon(icon: EvaIcons.star, title: 'Tab'), 87 | ], 88 | onSelect: (i) {}, 89 | ), 90 | ), 91 | ), 92 | ]; 93 | } 94 | -------------------------------------------------------------------------------- /lib/src/components/global/app/equinox_toast_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | /// Use this to push toasts using [EqToastService.of()]. 5 | /// 6 | /// ```dart 7 | /// EqToastService.of(context).pushToast(toast: EqToast(...)); 8 | /// ``` 9 | class EqToastService extends StatefulWidget { 10 | final Widget child; 11 | 12 | const EqToastService({Key key, this.child}) : super(key: key); 13 | 14 | @override 15 | EqToastServiceState createState() => EqToastServiceState(); 16 | 17 | static EqToastServiceState of(BuildContext context) { 18 | return (context.inheritFromWidgetOfExactType(_EqToastServiceInherited) 19 | as _EqToastServiceInherited) 20 | .data; 21 | } 22 | } 23 | 24 | class EqToastServiceState extends State { 25 | List _toastQueue; 26 | ScrollController _toastScrollController; 27 | 28 | @override 29 | void initState() { 30 | _toastQueue = []; 31 | _toastScrollController = ScrollController(); 32 | super.initState(); 33 | } 34 | 35 | @override 36 | void dispose() { 37 | _toastScrollController.dispose(); 38 | super.dispose(); 39 | } 40 | 41 | /// Removes a toast from the list. Refer to [EqToast] for styling info. 42 | void removeToast(EqToast toast) { 43 | _toastQueue.remove(toast); 44 | setState(() {}); 45 | } 46 | 47 | /// Pushes a new toast to the list. Refer to [EqToast] for styling info. 48 | void pushToast({EqToast toast}) { 49 | _toastQueue.add(toast); 50 | _toastScrollController.animateTo(0.0, 51 | duration: Duration(milliseconds: 300), curve: Curves.easeInOut); 52 | setState(() {}); 53 | } 54 | 55 | Widget _buildOverlay(BuildContext context) { 56 | var children = []; 57 | for (var toast in _toastQueue) { 58 | children.add( 59 | EqToastWidget( 60 | key: ValueKey(toast), 61 | data: toast, 62 | padding: const EdgeInsets.only(top: 16.0), 63 | serviceRemoveToastCallback: () => removeToast(toast), 64 | ), 65 | ); 66 | } 67 | 68 | return Container( 69 | alignment: Alignment.bottomRight, 70 | padding: const EdgeInsets.only( 71 | bottom: 48.0, 72 | top: 128.0, 73 | ), 74 | child: SingleChildScrollView( 75 | controller: _toastScrollController, 76 | reverse: true, 77 | padding: const EdgeInsets.only(left: 16.0, right: 16.0, bottom: 16.0), 78 | child: Column( 79 | mainAxisSize: MainAxisSize.min, 80 | crossAxisAlignment: CrossAxisAlignment.end, 81 | children: children, 82 | ), 83 | ), 84 | ); 85 | } 86 | 87 | @override 88 | Widget build(BuildContext context) { 89 | return _EqToastServiceInherited( 90 | data: this, 91 | child: Stack( 92 | children: [ 93 | widget.child, 94 | Align( 95 | alignment: Alignment.bottomRight, 96 | child: _buildOverlay(context), 97 | ), 98 | ], 99 | ), 100 | ); 101 | } 102 | } 103 | 104 | class _EqToastServiceInherited extends InheritedWidget { 105 | final EqToastServiceState data; 106 | final Widget child; 107 | 108 | _EqToastServiceInherited({Key key, this.child, this.data}) 109 | : super(key: key, child: child); 110 | 111 | @override 112 | bool updateShouldNotify(_EqToastServiceInherited oldWidget) => false; 113 | } 114 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at kk.erzhan@gmail.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /equinox_visualqa/lib/components/radio.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:equinox_visualqa/management/showcase_state.dart'; 4 | import 'package:equinox_visualqa/utils.dart'; 5 | import 'package:separated_column/separated_column.dart'; 6 | 7 | class RadioShowcase extends StatefulWidget { 8 | @override 9 | _RadioShowcaseState createState() => _RadioShowcaseState(); 10 | } 11 | 12 | class _RadioShowcaseState extends ShowcaseState { 13 | @override 14 | Widget playgroundBuilder() => SizedBox(); 15 | 16 | @override 17 | String get showcaseName => 'Radio'; 18 | 19 | Map status = {}; 20 | 21 | bool getStatus(String key, [bool def = false]) { 22 | if (status.containsKey(key)) return status[key]; 23 | status[key] = def; 24 | return def; 25 | } 26 | 27 | setStatus(String key) { 28 | status[key] = true; 29 | var prefix = key.split('.').first; 30 | for (final itemKey in status.keys) { 31 | if (itemKey.split('.').first == prefix && itemKey != key) { 32 | status[itemKey] = false; 33 | } 34 | } 35 | setState(() {}); 36 | } 37 | 38 | @override 39 | List get showcases => [ 40 | ShowcaseWidgetData( 41 | title: 'Radio', 42 | builder: () => SeparatedColumn( 43 | crossAxisAlignment: CrossAxisAlignment.start, 44 | children: [ 45 | EqRadio( 46 | value: getStatus('d.0'), 47 | onSelected: () => setStatus('d.0'), 48 | description: 'Description', 49 | ), 50 | EqRadio( 51 | value: getStatus('d.1'), 52 | onSelected: () => setStatus('d.1'), 53 | description: 'Description', 54 | ), 55 | EqRadio( 56 | value: false, 57 | onSelected: null, 58 | description: 'Disabled', 59 | ), 60 | ], 61 | separatorBuilder: (_, i) => SizedBox(height: 16.0), 62 | ), 63 | ), 64 | ShowcaseWidgetData( 65 | title: 'Radio colors', 66 | builder: () => SeparatedColumn( 67 | crossAxisAlignment: CrossAxisAlignment.start, 68 | children: EqWidgetStatus.values 69 | .map( 70 | (value) => EqRadio( 71 | value: getStatus(value.toString()), 72 | onSelected: () => setStatus(value.toString()), 73 | description: enumToString(value), 74 | status: value, 75 | ), 76 | ) 77 | .toList(), 78 | separatorBuilder: (_, i) => SizedBox(height: 16.0), 79 | ), 80 | ), 81 | ShowcaseWidgetData( 82 | title: 'Description location', 83 | builder: () => SeparatedColumn( 84 | crossAxisAlignment: CrossAxisAlignment.start, 85 | children: EqPositioning.values 86 | .map( 87 | (value) => EqRadio( 88 | value: getStatus(value.toString()), 89 | onSelected: () => setStatus(value.toString()), 90 | description: enumToString(value), 91 | descriptionPosition: value, 92 | ), 93 | ) 94 | .toList(), 95 | separatorBuilder: (_, i) => SizedBox(height: 16.0), 96 | ), 97 | ), 98 | ]; 99 | } 100 | -------------------------------------------------------------------------------- /example/lib/home_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class HomePage extends StatefulWidget { 5 | @override 6 | _HomePageState createState() => _HomePageState(); 7 | } 8 | 9 | class _HomePageState extends State { 10 | bool checked = false; 11 | 12 | Widget _buildBody() { 13 | return EqCard( 14 | shape: EqWidgetShape.semiRound, 15 | header: Text('Login'), 16 | child: Column( 17 | crossAxisAlignment: CrossAxisAlignment.start, 18 | mainAxisSize: MainAxisSize.min, 19 | children: [ 20 | EqTextField( 21 | label: 'Username', 22 | shape: EqWidgetShape.semiRound, 23 | hint: 'Username', 24 | icon: EvaIcons.emailOutline, 25 | iconPosition: EqPositioning.right, 26 | enabled: false, 27 | ), 28 | SizedBox(height: 16.0), 29 | EqTextField( 30 | label: 'Password', 31 | shape: EqWidgetShape.semiRound, 32 | hint: 'Password', 33 | icon: EvaIcons.lockOutline, 34 | iconPosition: EqPositioning.right, 35 | obscureText: true, 36 | ), 37 | SizedBox(height: 16.0), 38 | EqSelect( 39 | label: 'Select', 40 | hint: 'Select', 41 | shape: EqWidgetShape.semiRound, 42 | items: [ 43 | EqSelectItem( 44 | title: 'Option 1', 45 | value: '1', 46 | icon: EvaIcons.star, 47 | subtitle: 'Option 1'), 48 | EqSelectItem( 49 | title: 'Option 2', 50 | value: '2', 51 | icon: EvaIcons.archive, 52 | subtitle: 'Option 2'), 53 | ], 54 | onSelect: (v) { 55 | print(v); 56 | }, 57 | ), 58 | SizedBox(height: 16.0), 59 | EqCheckbox( 60 | value: checked, 61 | onChanged: (v) => setState(() => checked = v), 62 | description: 'Remember me', 63 | shape: EqWidgetShape.rectangle, 64 | ), 65 | ], 66 | ), 67 | footerPadding: EdgeInsets.zero, 68 | footer: EqButton( 69 | appearance: EqWidgetAppearance.ghost, 70 | onTap: () {}, 71 | label: Text('Log in'), 72 | size: EqWidgetSize.large, 73 | status: EqWidgetStatus.primary, 74 | ), 75 | ); 76 | } 77 | 78 | @override 79 | Widget build(BuildContext context) { 80 | return EqLayout( 81 | appBar: EqAppBar( 82 | centerTitle: true, 83 | title: 'Auth test', 84 | subtitle: 'v0.0.3', 85 | bottom: EqTabs( 86 | defaultSelected: 0, 87 | onSelect: (v) {}, 88 | tabs: [ 89 | EqTabData.fromIcon( 90 | icon: EvaIcons.star, 91 | title: 'Tab 1', 92 | ), 93 | EqTabData.fromIcon( 94 | icon: EvaIcons.star, 95 | title: 'Tab 2', 96 | ), 97 | EqTabData.fromIcon( 98 | icon: EvaIcons.star, 99 | title: 'Tab 3', 100 | ), 101 | EqTabData.fromIcon( 102 | icon: EvaIcons.star, 103 | title: 'Tab 4', 104 | ), 105 | ], 106 | ), 107 | ), 108 | child: Center( 109 | child: Padding( 110 | padding: const EdgeInsets.all(16.0), 111 | child: _buildBody(), 112 | ), 113 | ), 114 | ); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 56 | 58 | 64 | 65 | 66 | 67 | 68 | 69 | 75 | 77 | 83 | 84 | 85 | 86 | 88 | 89 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /equinox_visualqa/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 56 | 58 | 64 | 65 | 66 | 67 | 68 | 69 | 75 | 77 | 83 | 84 | 85 | 86 | 88 | 89 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /lib/src/theme/themings/text_style.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | import 'package:equinox/equinox.dart'; 3 | 4 | final StyleData textStyle = StyleData({ 5 | 'text-basic-color': 'color-basic-900', 6 | 'text-alternate-color': 'color-basic-100', 7 | 'text-control-color': 'color-basic-100', 8 | 'text-disabled-color': 'color-basic-500', 9 | 'text-hint-color': 'color-basic-600', 10 | 'text-primary-color': 'color-primary-default', 11 | 'text-primary-focus-color': 'color-primary-focus', 12 | 'text-primary-hover-color': 'color-primary-hover', 13 | 'text-primary-active-color': 'color-primary-active', 14 | 'text-primary-disabled-color': 'color-primary-400', 15 | 'text-success-color': 'color-success-default', 16 | 'text-success-focus-color': 'color-success-focus', 17 | 'text-success-hover-color': 'color-success-hover', 18 | 'text-success-active-color': 'color-success-active', 19 | 'text-success-disabled-color': 'color-success-400', 20 | 'text-info-color': 'color-info-default', 21 | 'text-info-focus-color': 'color-info-focus', 22 | 'text-info-hover-color': 'color-info-hover', 23 | 'text-info-active-color': 'color-info-active', 24 | 'text-info-disabled-color': 'color-info-400', 25 | 'text-warning-color': 'color-warning-default', 26 | 'text-warning-focus-color': 'color-warning-focus', 27 | 'text-warning-hover-color': 'color-warning-hover', 28 | 'text-warning-active-color': 'color-warning-active', 29 | 'text-warning-disabled-color': 'color-warning-400', 30 | 'text-danger-color': 'color-danger-default', 31 | 'text-danger-focus-color': 'color-danger-focus', 32 | 'text-danger-hover-color': 'color-danger-hover', 33 | 'text-danger-active-color': 'color-danger-active', 34 | 'text-danger-disabled-color': 'color-danger-400', 35 | 'font-family-primary': 'Roboto', 36 | 'font-family-secondary': 'Roboto', 37 | 'text-heading-1-font-family': 'font-family-secondary', 38 | 'text-heading-1-font-size': 2.25 * 16.0, 39 | 'text-heading-1-font-weight': FontWeight.w700, 40 | 'text-heading-2-font-family': 'font-family-secondary', 41 | 'text-heading-2-font-size': 2 * 16.0, 42 | 'text-heading-2-font-weight': FontWeight.w700, 43 | 'text-heading-3-font-family': 'font-family-secondary', 44 | 'text-heading-3-font-size': 1.875 * 16.0, 45 | 'text-heading-3-font-weight': FontWeight.w700, 46 | 'text-heading-4-font-family': 'font-family-secondary', 47 | 'text-heading-4-font-size': 1.625 * 16.0, 48 | 'text-heading-4-font-weight': FontWeight.w700, 49 | 'text-heading-5-font-family': 'font-family-secondary', 50 | 'text-heading-5-font-size': 1.375 * 16.0, 51 | 'text-heading-5-font-weight': FontWeight.w700, 52 | 'text-heading-6-font-family': 'font-family-secondary', 53 | 'text-heading-6-font-size': 1.125 * 16.0, 54 | 'text-heading-6-font-weight': FontWeight.w700, 55 | 'text-subtitle-font-family': 'font-family-primary', 56 | 'text-subtitle-font-size': 0.9375 * 16.0, 57 | 'text-subtitle-font-weight': FontWeight.w600, 58 | 'text-subtitle-2-font-family': 'font-family-primary', 59 | 'text-subtitle-2-font-size': 0.8125 * 16.0, 60 | 'text-subtitle-2-font-weight': FontWeight.w600, 61 | 'text-paragraph-font-family': 'font-family-primary', 62 | 'text-paragraph-font-size': 0.9375 * 16.0, 63 | 'text-paragraph-font-weight': FontWeight.w400, 64 | 'text-paragraph-2-font-family': 'font-family-primary', 65 | 'text-paragraph-2-font-size': 0.8125 * 16.0, 66 | 'text-paragraph-2-font-weight': FontWeight.w400, 67 | 'text-label-font-family': 'font-family-primary', 68 | 'text-label-font-size': 0.75 * 16.0, 69 | 'text-label-font-weight': FontWeight.w700, 70 | 'text-caption-font-family': 'font-family-primary', 71 | 'text-caption-font-size': 0.75 * 16.0, 72 | 'text-caption-font-weight': FontWeight.w400, 73 | 'text-caption-2-font-family': 'font-family-primary', 74 | 'text-caption-2-font-size': 0.75 * 16.0, 75 | 'text-caption-2-font-weight': FontWeight.w600, 76 | }); 77 | -------------------------------------------------------------------------------- /lib/src/components/icon_button/icon_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | export 'package:equinox/src/components/icon_button/icon_button_style.dart'; 3 | import 'package:equinox/src/equinox_internal.dart'; 4 | import 'package:flutter/widgets.dart'; 5 | 6 | /// This widget is used to display a button without a label. 7 | /// Customize this using [EqIconButtonThemeData]. 8 | class EqIconButton extends StatefulWidget { 9 | /// Controls the size of the button 10 | final EqWidgetSize size; 11 | 12 | /// Controls the colors. 13 | final EqWidgetStatus status; 14 | 15 | /// If provided, overwrites the color set by [status] in [WidgetAppearance.ghost] and 16 | /// [WidgetAppearance.outline] appearances. 17 | final Color color; 18 | 19 | /// Controls the appearance of the widget. 20 | final EqWidgetAppearance appearance; 21 | 22 | /// Controls the border radius. 23 | final EqWidgetShape shape; 24 | 25 | /// Method is called when user taps on the button. Can be null to disable this button. 26 | final VoidCallback onTap; 27 | 28 | /// Icon to display. 29 | final IconData icon; 30 | 31 | const EqIconButton({ 32 | Key key, 33 | @required this.icon, 34 | @required this.onTap, 35 | this.size = EqWidgetSize.medium, 36 | this.status, 37 | this.appearance = EqWidgetAppearance.filled, 38 | this.shape = EqWidgetShape.round, 39 | this.color, 40 | }) : super(key: key); 41 | 42 | @override 43 | _EqIconButtonState createState() => _EqIconButtonState(); 44 | } 45 | 46 | class _EqIconButtonState extends State { 47 | bool outlined = false; 48 | 49 | @override 50 | Widget build(BuildContext context) { 51 | final style = StaticStyle.of(context); 52 | 53 | final active = outlined; 54 | final disabled = widget.onTap == null; 55 | 56 | final selectorBase = ['icon-button', widget.appearance]; 57 | final selectorSizeBase = ['icon-button', widget.appearance, widget.size]; 58 | final selectorStateBase = [ 59 | 'icon-button', 60 | widget.appearance, 61 | widget.status, 62 | (disabled) ? 'disabled' : (active) ? 'active' : null, 63 | ]; 64 | 65 | return OutlinedWidget( 66 | outlined: outlined, 67 | borderRadius: BorderRadius.all(EqWidgetShapeUtils.getRadius( 68 | style: style.style, 69 | shape: widget.shape, 70 | )), 71 | clipInner: widget.appearance != EqWidgetAppearance.ghost, 72 | child: AnimatedContainer( 73 | duration: style.get('minor-animation-duration'), 74 | curve: style.get('minor-animation-curve'), 75 | decoration: BoxDecoration( 76 | color: style.get( 77 | generateSelector([...selectorStateBase, 'background-color'])), 78 | borderRadius: BorderRadius.all(EqWidgetShapeUtils.getRadius( 79 | style: style.style, 80 | shape: widget.shape, 81 | )), 82 | border: Border.all( 83 | width: style.get( 84 | generateSelector([...selectorBase, 'border-width']), 85 | ), 86 | color: style.get( 87 | generateSelector([...selectorStateBase, 'border-color']), 88 | ), 89 | ), 90 | ), 91 | child: OutlinedGestureDetector( 92 | onTap: widget.onTap, 93 | onOutlineChange: (v) => setState(() => outlined = v), 94 | child: Padding( 95 | padding: style.get( 96 | generateSelector([...selectorSizeBase, 'padding']), 97 | ), 98 | child: Icon( 99 | widget.icon, 100 | size: style.get( 101 | generateSelector(['icon-button', widget.size, 'icon-size'])), 102 | color: style 103 | .get(generateSelector([...selectorStateBase, 'icon-color'])), 104 | ), 105 | ), 106 | ), 107 | ), 108 | ); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /equinox_visualqa/lib/components/toast.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | import 'package:equinox_visualqa/management/showcase_state.dart'; 3 | import 'package:equinox_visualqa/utils.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:separated_column/separated_column.dart'; 6 | 7 | class ToastShowcase extends StatefulWidget { 8 | @override 9 | _ToastShowcaseState createState() => _ToastShowcaseState(); 10 | } 11 | 12 | class _ToastShowcaseState extends ShowcaseState { 13 | @override 14 | Widget playgroundBuilder() => InteractivePlayground( 15 | data: { 16 | 'subtitle': BoolTyped(true), 17 | 'icon': BoolTyped(true), 18 | 'status': EnumTyped(EqWidgetStatus.success, EqWidgetStatus.values), 19 | 'shape': EnumTyped(EqWidgetShape.semiRound, EqWidgetShape.values), 20 | }, 21 | builder: (_, data) { 22 | return SizedBox( 23 | width: double.infinity, 24 | child: EqButton( 25 | status: data['status'], 26 | shape: data['shape'], 27 | label: Text('Show toast'), 28 | onTap: () => showToast( 29 | EqToast( 30 | message: 'A message', 31 | subtitle: data['subtitle'] ? 'And a subtitle' : null, 32 | icon: data['icon'] ? EvaIcons.star : null, 33 | status: data['status'], 34 | shape: data['shape'], 35 | duration: Duration(seconds: 5), 36 | ), 37 | ), 38 | ), 39 | ); 40 | }, 41 | ); 42 | 43 | @override 44 | String get showcaseName => 'Toasts'; 45 | 46 | showToast(EqToast data) { 47 | EqToastService.of(context).pushToast(toast: data); 48 | } 49 | 50 | @override 51 | List get showcases { 52 | return [ 53 | ShowcaseWidgetData( 54 | title: 'Toasts', 55 | builder: () => EqButton( 56 | label: Text('Show toast'), 57 | onTap: () => showToast( 58 | EqToast( 59 | message: 'Hi! I am a toast.', 60 | subtitle: 'Click me to dismiss!', 61 | icon: EvaIcons.star, 62 | ), 63 | ), 64 | ), 65 | ), 66 | ShowcaseWidgetData( 67 | title: 'Toast colors', 68 | builder: () => SeparatedColumn( 69 | separatorBuilder: (_, i) => SizedBox(height: 8.0), 70 | children: EqWidgetStatus.values 71 | .map((value) => SizedBox( 72 | width: double.infinity, 73 | child: EqButton( 74 | status: value, 75 | label: Text('Show ${enumToString(value)} toast'), 76 | onTap: () => showToast( 77 | EqToast( 78 | message: 'Hi! I am a ${enumToString(value)} toast.', 79 | subtitle: 'Click me to dismiss!', 80 | status: value, 81 | icon: EvaIcons.star, 82 | ), 83 | ), 84 | ))) 85 | .toList(), 86 | ), 87 | ), 88 | ShowcaseWidgetData( 89 | title: 'Toast shapes', 90 | builder: () => SeparatedColumn( 91 | separatorBuilder: (_, i) => SizedBox(height: 8.0), 92 | children: EqWidgetShape.values 93 | .map((value) => SizedBox( 94 | width: double.infinity, 95 | child: EqButton( 96 | label: Text('Show ${enumToString(value)} toast'), 97 | onTap: () => showToast( 98 | EqToast( 99 | message: 'Hi! I am a ${enumToString(value)} toast.', 100 | subtitle: 'Click me to dismiss!', 101 | shape: value, 102 | icon: EvaIcons.star, 103 | ), 104 | ), 105 | ))) 106 | .toList(), 107 | ), 108 | ), 109 | ]; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "2.2.0" 11 | boolean_selector: 12 | dependency: transitive 13 | description: 14 | name: boolean_selector 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "1.0.4" 18 | charcode: 19 | dependency: transitive 20 | description: 21 | name: charcode 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "1.1.2" 25 | collection: 26 | dependency: transitive 27 | description: 28 | name: collection 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "1.14.11" 32 | eva_icons_flutter: 33 | dependency: "direct main" 34 | description: 35 | name: eva_icons_flutter 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "2.0.0" 39 | flutter: 40 | dependency: "direct main" 41 | description: flutter 42 | source: sdk 43 | version: "0.0.0" 44 | flutter_test: 45 | dependency: "direct dev" 46 | description: flutter 47 | source: sdk 48 | version: "0.0.0" 49 | matcher: 50 | dependency: transitive 51 | description: 52 | name: matcher 53 | url: "https://pub.dartlang.org" 54 | source: hosted 55 | version: "0.12.5" 56 | meta: 57 | dependency: transitive 58 | description: 59 | name: meta 60 | url: "https://pub.dartlang.org" 61 | source: hosted 62 | version: "1.1.6" 63 | path: 64 | dependency: transitive 65 | description: 66 | name: path 67 | url: "https://pub.dartlang.org" 68 | source: hosted 69 | version: "1.6.2" 70 | pedantic: 71 | dependency: transitive 72 | description: 73 | name: pedantic 74 | url: "https://pub.dartlang.org" 75 | source: hosted 76 | version: "1.7.0" 77 | quiver: 78 | dependency: transitive 79 | description: 80 | name: quiver 81 | url: "https://pub.dartlang.org" 82 | source: hosted 83 | version: "2.0.3" 84 | sky_engine: 85 | dependency: transitive 86 | description: flutter 87 | source: sdk 88 | version: "0.0.99" 89 | source_span: 90 | dependency: transitive 91 | description: 92 | name: source_span 93 | url: "https://pub.dartlang.org" 94 | source: hosted 95 | version: "1.5.5" 96 | stack_trace: 97 | dependency: transitive 98 | description: 99 | name: stack_trace 100 | url: "https://pub.dartlang.org" 101 | source: hosted 102 | version: "1.9.3" 103 | stream_channel: 104 | dependency: transitive 105 | description: 106 | name: stream_channel 107 | url: "https://pub.dartlang.org" 108 | source: hosted 109 | version: "2.0.0" 110 | string_scanner: 111 | dependency: transitive 112 | description: 113 | name: string_scanner 114 | url: "https://pub.dartlang.org" 115 | source: hosted 116 | version: "1.0.4" 117 | stylist: 118 | dependency: "direct main" 119 | description: 120 | name: stylist 121 | url: "https://pub.dartlang.org" 122 | source: hosted 123 | version: "0.0.4" 124 | term_glyph: 125 | dependency: transitive 126 | description: 127 | name: term_glyph 128 | url: "https://pub.dartlang.org" 129 | source: hosted 130 | version: "1.1.0" 131 | test_api: 132 | dependency: transitive 133 | description: 134 | name: test_api 135 | url: "https://pub.dartlang.org" 136 | source: hosted 137 | version: "0.2.5" 138 | typed_data: 139 | dependency: transitive 140 | description: 141 | name: typed_data 142 | url: "https://pub.dartlang.org" 143 | source: hosted 144 | version: "1.1.6" 145 | vector_math: 146 | dependency: "direct main" 147 | description: 148 | name: vector_math 149 | url: "https://pub.dartlang.org" 150 | source: hosted 151 | version: "2.0.8" 152 | sdks: 153 | dart: ">=2.2.2 <3.0.0" 154 | -------------------------------------------------------------------------------- /lib/src/components/global/app/equinox_dialog_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | import 'package:equinox/src/equinox_internal.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | /// This is used to show dialogs. Use it with [EqDialogService.of()]. 6 | class EqDialogService extends StatefulWidget { 7 | final Widget child; 8 | 9 | const EqDialogService({Key key, this.child}) : super(key: key); 10 | 11 | @override 12 | EqDialogServiceState createState() => EqDialogServiceState(); 13 | 14 | static EqDialogServiceState of(BuildContext context) { 15 | return (context.inheritFromWidgetOfExactType(_EqDialogServiceInherited) 16 | as _EqDialogServiceInherited) 17 | .data; 18 | } 19 | } 20 | 21 | class EqDialogServiceState extends State { 22 | @override 23 | void initState() { 24 | super.initState(); 25 | } 26 | 27 | @override 28 | void dispose() { 29 | super.dispose(); 30 | } 31 | 32 | /// Pushes a general dialog with title, body, and actions. [title], [body], [context], [actions] must not be null. 33 | Future pushDialog({ 34 | @required BuildContext context, 35 | @required String title, 36 | @required Widget body, 37 | List actions = const [], 38 | EqWidgetStatus status = EqWidgetStatus.primary, 39 | }) { 40 | return Navigator.of(context).push( 41 | TransparentPageRoute( 42 | builder: (context) => EqDialog( 43 | child: body, 44 | header: Text(title), 45 | status: status, 46 | footerPadding: EdgeInsets.zero, 47 | footer: actions != null 48 | ? Wrap( 49 | spacing: 8.0, 50 | runSpacing: 8.0, 51 | alignment: WrapAlignment.end, 52 | children: actions, 53 | ) 54 | : null, 55 | ), 56 | ), 57 | ); 58 | } 59 | 60 | /// Pushes a custom dialog. Refer to [EqDialog] for styling info. [dialog] and [context] must not be null. 61 | Future pushCustomDialog({ 62 | @required BuildContext context, 63 | @required EqDialog dialog, 64 | }) { 65 | return Navigator.of(context).push( 66 | TransparentPageRoute( 67 | builder: (_) => dialog, 68 | ), 69 | ); 70 | } 71 | 72 | /// Pushes an informational dialog. [title], [body], [context] must not be null. Provides 'close' button on bottom. 73 | Future pushInformationDialog({ 74 | @required BuildContext context, 75 | @required String title, 76 | @required Widget body, 77 | EqWidgetStatus status = EqWidgetStatus.info, 78 | }) async { 79 | return Navigator.of(context).push( 80 | TransparentPageRoute( 81 | builder: (context) => EqDialog( 82 | child: body, 83 | header: Text(title), 84 | footerPadding: EdgeInsets.zero, 85 | status: status, 86 | footer: EqButton( 87 | onTap: () => Navigator.of(context).pop(), 88 | appearance: EqWidgetAppearance.ghost, 89 | label: Text('Close'), 90 | status: status, 91 | ), 92 | ), 93 | ), 94 | ); 95 | } 96 | 97 | /// Pushes a loading dialog. [context] must not be null. 98 | pushLoadingDialog({ 99 | @required BuildContext context, 100 | EqWidgetStatus status = EqWidgetStatus.primary, 101 | }) { 102 | return Navigator.of(context).push( 103 | TransparentPageRoute( 104 | builder: (context) => EqCard( 105 | shape: EqWidgetShape.round, 106 | child: EqSpinner( 107 | status: status, 108 | ), 109 | ), 110 | ), 111 | ); 112 | } 113 | 114 | @override 115 | Widget build(BuildContext context) { 116 | return _EqDialogServiceInherited( 117 | data: this, 118 | child: widget.child, 119 | ); 120 | } 121 | } 122 | 123 | class _EqDialogServiceInherited extends InheritedWidget { 124 | final EqDialogServiceState data; 125 | final Widget child; 126 | 127 | _EqDialogServiceInherited({Key key, this.child, this.data}) 128 | : super(key: key, child: child); 129 | 130 | @override 131 | bool updateShouldNotify(_EqDialogServiceInherited oldWidget) => false; 132 | } 133 | -------------------------------------------------------------------------------- /lib/src/components/list_item/list_item.dart: -------------------------------------------------------------------------------- 1 | import 'package:equinox/equinox.dart'; 2 | import 'package:equinox/src/equinox_internal.dart'; 3 | import 'package:flutter/widgets.dart'; 4 | 5 | export 'package:equinox/src/components/list_item/list_item_style.dart'; 6 | 7 | /// EqListItem is used to display a line of information, typically in a list. 8 | class EqListItem extends StatefulWidget { 9 | /// Icon to display before the content. 10 | final IconData icon; 11 | 12 | /// The main information of this item. 13 | final String title; 14 | 15 | /// Additional information. 16 | final String subtitle; 17 | 18 | /// Active means that this list item is highlighted (selected). 19 | final bool active; 20 | 21 | /// Controls the colors. 22 | final EqWidgetStatus status; 23 | 24 | /// This method is called when user presses the item. 25 | final VoidCallback onTap; 26 | 27 | /// Padding to use in this list item. 28 | final EdgeInsets padding; 29 | 30 | const EqListItem({ 31 | Key key, 32 | this.icon, 33 | @required this.title, 34 | @required this.onTap, 35 | this.subtitle, 36 | this.status = EqWidgetStatus.primary, 37 | this.active = false, 38 | this.padding, 39 | }) : super(key: key); 40 | 41 | @override 42 | _EqListItemState createState() => _EqListItemState(); 43 | } 44 | 45 | class _EqListItemState extends State { 46 | bool isPressing = false; 47 | 48 | @override 49 | Widget build(BuildContext context) { 50 | final style = StaticStyle.of(context); 51 | final active = widget.active; 52 | final focused = isPressing; 53 | final disabled = widget.onTap == null; 54 | return OutlinedGestureDetector( 55 | onTap: widget.onTap, 56 | onOutlineChange: (v) => setState(() => isPressing = v), 57 | child: Container( 58 | padding: widget.padding ?? const EdgeInsets.all(16.0), 59 | child: Row( 60 | children: [ 61 | if (widget.icon != null) ...[ 62 | Icon(widget.icon, 63 | color: style.get(generateSelector([ 64 | 'list-item-icon', 65 | (disabled) ? 'disabled' : widget.status, 66 | (focused) ? 'focused' : (active) ? 'active' : null, 67 | 'color' 68 | ]))), 69 | SizedBox(width: 16.0), 70 | ], 71 | Column( 72 | crossAxisAlignment: CrossAxisAlignment.start, 73 | children: [ 74 | Text( 75 | widget.title, 76 | style: TextStyle( 77 | fontWeight: style.get('list-item-title-font-weight'), 78 | fontSize: style.get('list-item-title-font-size'), 79 | fontFamily: style.get('list-item-title-font-family'), 80 | color: style.get(generateSelector([ 81 | 'list-item-title', 82 | (disabled) ? 'disabled' : widget.status, 83 | (focused) 84 | ? 'focused' 85 | : (active && !disabled) ? 'active' : null, 86 | 'color' 87 | ])), 88 | ), 89 | ), 90 | if (widget.subtitle != null) 91 | Text( 92 | widget.subtitle, 93 | style: TextStyle( 94 | fontWeight: style.get('list-item-subtitle-font-weight'), 95 | fontSize: style.get('list-item-subtitle-font-size'), 96 | fontFamily: style.get('list-item-subtitle-font-family'), 97 | color: style.get(generateSelector([ 98 | 'list-item-subtitle', 99 | (disabled) ? 'disabled' : widget.status, 100 | (focused) 101 | ? 'focused' 102 | : (active && !disabled) ? 'active' : null, 103 | 'color' 104 | ])), 105 | ), 106 | ), 107 | ], 108 | ), 109 | ], 110 | ), 111 | ), 112 | ); 113 | } 114 | } 115 | --------------------------------------------------------------------------------