diff --git a/.cursorignore b/.cursorignore new file mode 100644 index 000000000..e69de29bb diff --git a/.fvm/fvm_config.json b/.fvm/fvm_config.json deleted file mode 100644 index b3db758e4..000000000 --- a/.fvm/fvm_config.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "flutterSdkVersion": "stable", - "flavors": {} -} \ No newline at end of file diff --git a/.fvmrc b/.fvmrc new file mode 100644 index 000000000..c300356c3 --- /dev/null +++ b/.fvmrc @@ -0,0 +1,3 @@ +{ + "flutter": "stable" +} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 130a0e14e..193ce1352 100644 --- a/.gitignore +++ b/.gitignore @@ -16,9 +16,7 @@ doc/ *.iws .idea/ - # FVM -.fvm/flutter_sdk # The .vscode folder contains launch configuration and tasks you configure in # VS Code which you may wish to be included in version control, so this line @@ -83,4 +81,7 @@ yarn.lock node_modules # FVM -.fvm/flutter_sdk \ No newline at end of file + +# FVM Version Cache +.fvm/ +**/**.context.md diff --git a/.vscode/settings.json b/.vscode/settings.json index 9d895d2a8..200a0b0da 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,15 +1,37 @@ { - "dart.flutterSdkPath": ".fvm/flutter_sdk", - // Remove .fvm files from search + "editor.codeActionsOnSave": { + "source.organizeImports": true, + "source.fixAll": true, + "source.dcm.fixAll": true + }, + "dart.flutterSdkPath": ".fvm/versions/stable", "search.exclude": { - "**/.fvm": true + "**/.fvm/versions": true }, - // Remove from file watching "files.watcherExclude": { - "**/.fvm": true + "**/.fvm/versions": true }, - "editor.codeActionsOnSave": { - "source.organizeImports": true, - "source.fixAll": true - } -} + "files.exclude": { + "**/.fvm/versions": true + }, + "workbench.colorCustomizations": { + "activityBar.activeBackground": "#0a1a34", + "activityBar.background": "#0a1a34", + "activityBar.foreground": "#e7e7e7", + "activityBar.inactiveForeground": "#e7e7e799", + "activityBarBadge.background": "#a01f50", + "activityBarBadge.foreground": "#e7e7e7", + "commandCenter.border": "#e7e7e799", + "sash.hoverBorder": "#0a1a34", + "statusBar.background": "#02050a", + "statusBar.foreground": "#e7e7e7", + "statusBarItem.hoverBackground": "#0a1a34", + "statusBarItem.remoteBackground": "#02050a", + "statusBarItem.remoteForeground": "#e7e7e7", + "titleBar.activeBackground": "#02050a", + "titleBar.activeForeground": "#e7e7e7", + "titleBar.inactiveBackground": "#02050a99", + "titleBar.inactiveForeground": "#e7e7e799" + }, + "peacock.color": "#02050a" +} \ No newline at end of file diff --git a/analysis_options.yaml b/analysis_options.yaml index b827dfb14..eff801de3 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,6 +1,4 @@ -# Defines a default set of lint rules enforced for -# projects at Google. For details and rationale, -# see https://github.com/dart-lang/pedantic#enabled-lints. + include: package:flutter_lints/flutter.yaml # For lint rules and documentation, see http://dart-lang.github.io/linter/lints. @@ -11,23 +9,63 @@ linter: prefer_relative_imports: true analyzer: - plugins: - - dart_code_metrics + exclude: + - "**/*.g.dart" + - "**/*.freezed.dart" + + dart_code_metrics: - metrics: - cyclomatic-complexity: 20 - number-of-parameters: 4 - maximum-nesting-level: 5 + extends: + - package:dart_code_metrics_presets/all.yaml metrics-exclude: - test/** + rules-exclude: + - "test/**" rules: - - newline-before-return - - no-boolean-literal-compare - - no-empty-block - - prefer-trailing-comma - - no-equal-then-else + prefer-match-file-name: false + prefer-single-widget-per-file: false + parameters-ordering: false + arguments-ordering: + child-last: true + avoid-dynamic: false + prefer-getter-over-method: false + enum-constants-ordering: false + prefer-widget-private-members: false + prefer-static-class: false + avoid-late-keyword: false + avoid-barrel-files: false + avoid-declaring-call-method: false + avoid-long-parameter-list: false + avoid-recursive-calls: false + no-magic-number: false + avoid-ignoring-return-values: false + prefer-commenting-analyzer-ignores: false + prefer-correct-identifier-length: false + avoid-unsafe-collection-methods: false + avoid-similar-names: false + format-comment: false + no-equal-arguments: false + prefer_initializing_formals: false + avoid-nested-conditional-expressions: + acceptable-level: 3 + member-ordering: + order: + - public-fields + - private-fields + - constructors + - static-methods + - public-getters + - private-getters + - public-setters + - private-setters + - public-methods + - private-methods + - overridden-public-methods + - overridden-public-getters + - build-method + prefer-named-boolean-parameters: + ignore-single: true + - anti-patterns: - - long-method - - long-parameter-list + \ No newline at end of file diff --git a/benchmarks/.gitignore b/benchmarks/.gitignore deleted file mode 100644 index 3c8a15727..000000000 --- a/benchmarks/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -# Files and directories created by pub. -.dart_tool/ -.packages - -# Conventional directory for build output. -build/ diff --git a/benchmarks/.metadata b/benchmarks/.metadata deleted file mode 100644 index 228db5762..000000000 --- a/benchmarks/.metadata +++ /dev/null @@ -1,45 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled. - -version: - revision: e99c9c7cd9f6c0b2f8ae6e3ebfd585239f5568f4 - channel: stable - -project_type: app - -# Tracks metadata for the flutter migrate command -migration: - platforms: - - platform: root - create_revision: e99c9c7cd9f6c0b2f8ae6e3ebfd585239f5568f4 - base_revision: e99c9c7cd9f6c0b2f8ae6e3ebfd585239f5568f4 - - platform: android - create_revision: e99c9c7cd9f6c0b2f8ae6e3ebfd585239f5568f4 - base_revision: e99c9c7cd9f6c0b2f8ae6e3ebfd585239f5568f4 - - platform: ios - create_revision: e99c9c7cd9f6c0b2f8ae6e3ebfd585239f5568f4 - base_revision: e99c9c7cd9f6c0b2f8ae6e3ebfd585239f5568f4 - - platform: linux - create_revision: e99c9c7cd9f6c0b2f8ae6e3ebfd585239f5568f4 - base_revision: e99c9c7cd9f6c0b2f8ae6e3ebfd585239f5568f4 - - platform: macos - create_revision: e99c9c7cd9f6c0b2f8ae6e3ebfd585239f5568f4 - base_revision: e99c9c7cd9f6c0b2f8ae6e3ebfd585239f5568f4 - - platform: web - create_revision: e99c9c7cd9f6c0b2f8ae6e3ebfd585239f5568f4 - base_revision: e99c9c7cd9f6c0b2f8ae6e3ebfd585239f5568f4 - - platform: windows - create_revision: e99c9c7cd9f6c0b2f8ae6e3ebfd585239f5568f4 - base_revision: e99c9c7cd9f6c0b2f8ae6e3ebfd585239f5568f4 - - # User provided section - - # List of Local paths (relative to this file) that should be - # ignored by the migrate tool. - # - # Files that are not part of the templates will be ignored by default. - unmanaged_files: - - 'lib/main.dart' - - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/benchmarks/CHANGELOG.md b/benchmarks/CHANGELOG.md deleted file mode 100644 index effe43c82..000000000 --- a/benchmarks/CHANGELOG.md +++ /dev/null @@ -1,3 +0,0 @@ -## 1.0.0 - -- Initial version. diff --git a/benchmarks/README.md b/benchmarks/README.md deleted file mode 100644 index f03f1e502..000000000 --- a/benchmarks/README.md +++ /dev/null @@ -1,11 +0,0 @@ -A list of benchmarks to measure the different aspects of Mix - -To run a benchmark, run: - -```sh -flutter run --release -t lib/some_benchmark.dart -``` - -#### Resources - -* \ No newline at end of file diff --git a/benchmarks/analysis_options.yaml b/benchmarks/analysis_options.yaml deleted file mode 100644 index dee8927aa..000000000 --- a/benchmarks/analysis_options.yaml +++ /dev/null @@ -1,30 +0,0 @@ -# This file configures the static analysis results for your project (errors, -# warnings, and lints). -# -# This enables the 'recommended' set of lints from `package:lints`. -# This set helps identify many issues that may lead to problems when running -# or consuming Dart code, and enforces writing Dart using a single, idiomatic -# style and format. -# -# If you want a smaller set of lints you can change this to specify -# 'package:lints/core.yaml'. These are just the most critical lints -# (the recommended set includes the core lints). -# The core lints are also what is used by pub.dev for scoring packages. - -include: package:lints/recommended.yaml - -# Uncomment the following section to specify additional rules. - -# linter: -# rules: -# - camel_case_types - -# analyzer: -# exclude: -# - path/to/excluded/files/** - -# For more information about the core and recommended set of lints, see -# https://dart.dev/go/core-lints - -# For additional information about configuring this file, see -# https://dart.dev/guides/language/analysis-options diff --git a/benchmarks/android/.gitignore b/benchmarks/android/.gitignore deleted file mode 100644 index 6f568019d..000000000 --- a/benchmarks/android/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -gradle-wrapper.jar -/.gradle -/captures/ -/gradlew -/gradlew.bat -/local.properties -GeneratedPluginRegistrant.java - -# Remember to never publicly share your keystore. -# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app -key.properties -**/*.keystore -**/*.jks diff --git a/benchmarks/android/app/build.gradle b/benchmarks/android/app/build.gradle deleted file mode 100644 index d166d7f93..000000000 --- a/benchmarks/android/app/build.gradle +++ /dev/null @@ -1,71 +0,0 @@ -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - -android { - compileSdkVersion flutter.compileSdkVersion - ndkVersion flutter.ndkVersion - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - - kotlinOptions { - jvmTarget = '1.8' - } - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - - defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.example.benchmarks" - // You can update the following values to match your application needs. - // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration. - minSdkVersion flutter.minSdkVersion - targetSdkVersion flutter.targetSdkVersion - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - } - - buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug - } - } -} - -flutter { - source '../..' -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" -} diff --git a/benchmarks/android/app/src/debug/AndroidManifest.xml b/benchmarks/android/app/src/debug/AndroidManifest.xml deleted file mode 100644 index 6c5d6ad67..000000000 --- a/benchmarks/android/app/src/debug/AndroidManifest.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - diff --git a/benchmarks/android/app/src/main/AndroidManifest.xml b/benchmarks/android/app/src/main/AndroidManifest.xml deleted file mode 100644 index 444c39cf5..000000000 --- a/benchmarks/android/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - diff --git a/benchmarks/android/app/src/main/kotlin/com/example/benchmarks/MainActivity.kt b/benchmarks/android/app/src/main/kotlin/com/example/benchmarks/MainActivity.kt deleted file mode 100644 index 8d1e404e1..000000000 --- a/benchmarks/android/app/src/main/kotlin/com/example/benchmarks/MainActivity.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.example.benchmarks - -import io.flutter.embedding.android.FlutterActivity - -class MainActivity: FlutterActivity() { -} diff --git a/benchmarks/android/app/src/main/res/drawable-v21/launch_background.xml b/benchmarks/android/app/src/main/res/drawable-v21/launch_background.xml deleted file mode 100644 index f74085f3f..000000000 --- a/benchmarks/android/app/src/main/res/drawable-v21/launch_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/benchmarks/android/app/src/main/res/drawable/launch_background.xml b/benchmarks/android/app/src/main/res/drawable/launch_background.xml deleted file mode 100644 index 304732f88..000000000 --- a/benchmarks/android/app/src/main/res/drawable/launch_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/benchmarks/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/benchmarks/android/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index db77bb4b7..000000000 Binary files a/benchmarks/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/benchmarks/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/benchmarks/android/app/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 17987b79b..000000000 Binary files a/benchmarks/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/benchmarks/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/benchmarks/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 09d439148..000000000 Binary files a/benchmarks/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/benchmarks/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/benchmarks/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index d5f1c8d34..000000000 Binary files a/benchmarks/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/benchmarks/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/benchmarks/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 4d6372eeb..000000000 Binary files a/benchmarks/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/benchmarks/android/app/src/main/res/values-night/styles.xml b/benchmarks/android/app/src/main/res/values-night/styles.xml deleted file mode 100644 index 06952be74..000000000 --- a/benchmarks/android/app/src/main/res/values-night/styles.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - diff --git a/benchmarks/android/app/src/main/res/values/styles.xml b/benchmarks/android/app/src/main/res/values/styles.xml deleted file mode 100644 index cb1ef8805..000000000 --- a/benchmarks/android/app/src/main/res/values/styles.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - diff --git a/benchmarks/android/app/src/profile/AndroidManifest.xml b/benchmarks/android/app/src/profile/AndroidManifest.xml deleted file mode 100644 index 6c5d6ad67..000000000 --- a/benchmarks/android/app/src/profile/AndroidManifest.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - diff --git a/benchmarks/android/build.gradle b/benchmarks/android/build.gradle deleted file mode 100644 index 83ae22004..000000000 --- a/benchmarks/android/build.gradle +++ /dev/null @@ -1,31 +0,0 @@ -buildscript { - ext.kotlin_version = '1.6.10' - repositories { - google() - mavenCentral() - } - - dependencies { - classpath 'com.android.tools.build:gradle:7.1.2' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - -allprojects { - repositories { - google() - mavenCentral() - } -} - -rootProject.buildDir = '../build' -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(':app') -} - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/benchmarks/android/gradle.properties b/benchmarks/android/gradle.properties deleted file mode 100644 index 94adc3a3f..000000000 --- a/benchmarks/android/gradle.properties +++ /dev/null @@ -1,3 +0,0 @@ -org.gradle.jvmargs=-Xmx1536M -android.useAndroidX=true -android.enableJetifier=true diff --git a/benchmarks/android/gradle/wrapper/gradle-wrapper.properties b/benchmarks/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index cb24abda1..000000000 --- a/benchmarks/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip diff --git a/benchmarks/android/settings.gradle b/benchmarks/android/settings.gradle deleted file mode 100644 index 44e62bcf0..000000000 --- a/benchmarks/android/settings.gradle +++ /dev/null @@ -1,11 +0,0 @@ -include ':app' - -def localPropertiesFile = new File(rootProject.projectDir, "local.properties") -def properties = new Properties() - -assert localPropertiesFile.exists() -localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } - -def flutterSdkPath = properties.getProperty("flutter.sdk") -assert flutterSdkPath != null, "flutter.sdk not set in local.properties" -apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/benchmarks/ios/.gitignore b/benchmarks/ios/.gitignore deleted file mode 100644 index 7a7f9873a..000000000 --- a/benchmarks/ios/.gitignore +++ /dev/null @@ -1,34 +0,0 @@ -**/dgph -*.mode1v3 -*.mode2v3 -*.moved-aside -*.pbxuser -*.perspectivev3 -**/*sync/ -.sconsign.dblite -.tags* -**/.vagrant/ -**/DerivedData/ -Icon? -**/Pods/ -**/.symlinks/ -profile -xcuserdata -**/.generated/ -Flutter/App.framework -Flutter/Flutter.framework -Flutter/Flutter.podspec -Flutter/Generated.xcconfig -Flutter/ephemeral/ -Flutter/app.flx -Flutter/app.zip -Flutter/flutter_assets/ -Flutter/flutter_export_environment.sh -ServiceDefinitions.json -Runner/GeneratedPluginRegistrant.* - -# Exceptions to above rules. -!default.mode1v3 -!default.mode2v3 -!default.pbxuser -!default.perspectivev3 diff --git a/benchmarks/ios/Flutter/AppFrameworkInfo.plist b/benchmarks/ios/Flutter/AppFrameworkInfo.plist deleted file mode 100644 index 9625e105d..000000000 --- a/benchmarks/ios/Flutter/AppFrameworkInfo.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - App - CFBundleIdentifier - io.flutter.flutter.app - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - App - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - MinimumOSVersion - 11.0 - - diff --git a/benchmarks/ios/Flutter/Debug.xcconfig b/benchmarks/ios/Flutter/Debug.xcconfig deleted file mode 100644 index 592ceee85..000000000 --- a/benchmarks/ios/Flutter/Debug.xcconfig +++ /dev/null @@ -1 +0,0 @@ -#include "Generated.xcconfig" diff --git a/benchmarks/ios/Flutter/Release.xcconfig b/benchmarks/ios/Flutter/Release.xcconfig deleted file mode 100644 index 592ceee85..000000000 --- a/benchmarks/ios/Flutter/Release.xcconfig +++ /dev/null @@ -1 +0,0 @@ -#include "Generated.xcconfig" diff --git a/benchmarks/ios/Runner.xcodeproj/project.pbxproj b/benchmarks/ios/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index 57e751d68..000000000 --- a/benchmarks/ios/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,481 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 50; - objects = { - -/* Begin PBXBuildFile section */ - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; -/* End PBXBuildFile section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 9705A1C41CF9048500538489 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; - 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 97C146EB1CF9000F007C117D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 9740EEB11CF90186004384FC /* Flutter */ = { - isa = PBXGroup; - children = ( - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 9740EEB31CF90195004384FC /* Generated.xcconfig */, - ); - name = Flutter; - sourceTree = ""; - }; - 97C146E51CF9000F007C117D = { - isa = PBXGroup; - children = ( - 9740EEB11CF90186004384FC /* Flutter */, - 97C146F01CF9000F007C117D /* Runner */, - 97C146EF1CF9000F007C117D /* Products */, - ); - sourceTree = ""; - }; - 97C146EF1CF9000F007C117D /* Products */ = { - isa = PBXGroup; - children = ( - 97C146EE1CF9000F007C117D /* Runner.app */, - ); - name = Products; - sourceTree = ""; - }; - 97C146F01CF9000F007C117D /* Runner */ = { - isa = PBXGroup; - children = ( - 97C146FA1CF9000F007C117D /* Main.storyboard */, - 97C146FD1CF9000F007C117D /* Assets.xcassets */, - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, - 97C147021CF9000F007C117D /* Info.plist */, - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, - ); - path = Runner; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 97C146ED1CF9000F007C117D /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - 9740EEB61CF901F6004384FC /* Run Script */, - 97C146EA1CF9000F007C117D /* Sources */, - 97C146EB1CF9000F007C117D /* Frameworks */, - 97C146EC1CF9000F007C117D /* Resources */, - 9705A1C41CF9048500538489 /* Embed Frameworks */, - 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Runner; - productName = Runner; - productReference = 97C146EE1CF9000F007C117D /* Runner.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 97C146E61CF9000F007C117D /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 1300; - ORGANIZATIONNAME = ""; - TargetAttributes = { - 97C146ED1CF9000F007C117D = { - CreatedOnToolsVersion = 7.3.1; - LastSwiftMigration = 1100; - }; - }; - }; - buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 9.3"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 97C146E51CF9000F007C117D; - productRefGroup = 97C146EF1CF9000F007C117D /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 97C146ED1CF9000F007C117D /* Runner */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 97C146EC1CF9000F007C117D /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Thin Binary"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; - }; - 9740EEB61CF901F6004384FC /* Run Script */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Run Script"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 97C146EA1CF9000F007C117D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - 97C146FA1CF9000F007C117D /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C146FB1CF9000F007C117D /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C147001CF9000F007C117D /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 249021D3217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Profile; - }; - 249021D4217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.benchmarks; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Profile; - }; - 97C147031CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 97C147041CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 97C147061CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.benchmarks; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Debug; - }; - 97C147071CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.benchmarks; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147031CF9000F007C117D /* Debug */, - 97C147041CF9000F007C117D /* Release */, - 249021D3217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147061CF9000F007C117D /* Debug */, - 97C147071CF9000F007C117D /* Release */, - 249021D4217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 97C146E61CF9000F007C117D /* Project object */; -} diff --git a/benchmarks/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/benchmarks/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a62..000000000 --- a/benchmarks/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/benchmarks/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/benchmarks/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003..000000000 --- a/benchmarks/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/benchmarks/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/benchmarks/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c5e..000000000 --- a/benchmarks/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/benchmarks/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/benchmarks/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100644 index c87d15a33..000000000 --- a/benchmarks/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/benchmarks/ios/Runner.xcworkspace/contents.xcworkspacedata b/benchmarks/ios/Runner.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 1d526a16e..000000000 --- a/benchmarks/ios/Runner.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/benchmarks/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/benchmarks/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003..000000000 --- a/benchmarks/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/benchmarks/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/benchmarks/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c5e..000000000 --- a/benchmarks/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/benchmarks/ios/Runner/AppDelegate.swift b/benchmarks/ios/Runner/AppDelegate.swift deleted file mode 100644 index 70693e4a8..000000000 --- a/benchmarks/ios/Runner/AppDelegate.swift +++ /dev/null @@ -1,13 +0,0 @@ -import UIKit -import Flutter - -@UIApplicationMain -@objc class AppDelegate: FlutterAppDelegate { - override func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? - ) -> Bool { - GeneratedPluginRegistrant.register(with: self) - return super.application(application, didFinishLaunchingWithOptions: launchOptions) - } -} diff --git a/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index d36b1fab2..000000000 --- a/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,122 +0,0 @@ -{ - "images" : [ - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@3x.png", - "scale" : "3x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@3x.png", - "scale" : "3x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@3x.png", - "scale" : "3x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@3x.png", - "scale" : "3x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@1x.png", - "scale" : "1x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@1x.png", - "scale" : "1x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@1x.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@2x.png", - "scale" : "2x" - }, - { - "size" : "83.5x83.5", - "idiom" : "ipad", - "filename" : "Icon-App-83.5x83.5@2x.png", - "scale" : "2x" - }, - { - "size" : "1024x1024", - "idiom" : "ios-marketing", - "filename" : "Icon-App-1024x1024@1x.png", - "scale" : "1x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png deleted file mode 100644 index dc9ada472..000000000 Binary files a/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png and /dev/null differ diff --git a/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png deleted file mode 100644 index 28c6bf030..000000000 Binary files a/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and /dev/null differ diff --git a/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png deleted file mode 100644 index 2ccbfd967..000000000 Binary files a/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and /dev/null differ diff --git a/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png deleted file mode 100644 index f091b6b0b..000000000 Binary files a/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and /dev/null differ diff --git a/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png deleted file mode 100644 index 4cde12118..000000000 Binary files a/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and /dev/null differ diff --git a/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png deleted file mode 100644 index d0ef06e7e..000000000 Binary files a/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and /dev/null differ diff --git a/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png deleted file mode 100644 index dcdc2306c..000000000 Binary files a/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and /dev/null differ diff --git a/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png deleted file mode 100644 index 2ccbfd967..000000000 Binary files a/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and /dev/null differ diff --git a/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png deleted file mode 100644 index c8f9ed8f5..000000000 Binary files a/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and /dev/null differ diff --git a/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png deleted file mode 100644 index a6d6b8609..000000000 Binary files a/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and /dev/null differ diff --git a/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png deleted file mode 100644 index a6d6b8609..000000000 Binary files a/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and /dev/null differ diff --git a/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png deleted file mode 100644 index 75b2d164a..000000000 Binary files a/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and /dev/null differ diff --git a/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png deleted file mode 100644 index c4df70d39..000000000 Binary files a/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and /dev/null differ diff --git a/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png deleted file mode 100644 index 6a84f41e1..000000000 Binary files a/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and /dev/null differ diff --git a/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png deleted file mode 100644 index d0e1f5853..000000000 Binary files a/benchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and /dev/null differ diff --git a/benchmarks/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/benchmarks/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json deleted file mode 100644 index 0bedcf2fd..000000000 --- a/benchmarks/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "LaunchImage.png", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "LaunchImage@2x.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "LaunchImage@3x.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/benchmarks/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/benchmarks/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png deleted file mode 100644 index 9da19eaca..000000000 Binary files a/benchmarks/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png and /dev/null differ diff --git a/benchmarks/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/benchmarks/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png deleted file mode 100644 index 9da19eaca..000000000 Binary files a/benchmarks/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png and /dev/null differ diff --git a/benchmarks/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/benchmarks/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png deleted file mode 100644 index 9da19eaca..000000000 Binary files a/benchmarks/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png and /dev/null differ diff --git a/benchmarks/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/benchmarks/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md deleted file mode 100644 index 89c2725b7..000000000 --- a/benchmarks/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Launch Screen Assets - -You can customize the launch screen with your own desired assets by replacing the image files in this directory. - -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. \ No newline at end of file diff --git a/benchmarks/ios/Runner/Base.lproj/LaunchScreen.storyboard b/benchmarks/ios/Runner/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index f2e259c7c..000000000 --- a/benchmarks/ios/Runner/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/benchmarks/ios/Runner/Base.lproj/Main.storyboard b/benchmarks/ios/Runner/Base.lproj/Main.storyboard deleted file mode 100644 index f3c28516f..000000000 --- a/benchmarks/ios/Runner/Base.lproj/Main.storyboard +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/benchmarks/ios/Runner/Info.plist b/benchmarks/ios/Runner/Info.plist deleted file mode 100644 index c036bdb41..000000000 --- a/benchmarks/ios/Runner/Info.plist +++ /dev/null @@ -1,51 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - Benchmarks - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - benchmarks - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleSignature - ???? - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance - - CADisableMinimumFrameDurationOnPhone - - UIApplicationSupportsIndirectInputEvents - - - diff --git a/benchmarks/ios/Runner/Runner-Bridging-Header.h b/benchmarks/ios/Runner/Runner-Bridging-Header.h deleted file mode 100644 index 308a2a560..000000000 --- a/benchmarks/ios/Runner/Runner-Bridging-Header.h +++ /dev/null @@ -1 +0,0 @@ -#import "GeneratedPluginRegistrant.h" diff --git a/benchmarks/lib/common.dart b/benchmarks/lib/common.dart deleted file mode 100644 index b414dd08b..000000000 --- a/benchmarks/lib/common.dart +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// Original file: https://raw.githubusercontent.com/flutter/flutter/master/dev/benchmarks/microbenchmarks/lib/common.dart -// Access in November 21st, 2022 - -import 'dart:convert' show json; -import 'dart:math' as math; - -double _doNormal( - {required double mean, required double stddev, required double x}) { - return (1.0 / (stddev * math.sqrt(2.0 * math.pi))) * - math.pow(math.e, -0.5 * math.pow((x - mean) / stddev, 2.0)); -} - -double _doMean(List values) => - values.reduce((double x, double y) => x + y) / values.length; - -double _doStddev(List values, double mean) { - double stddev = 0.0; - for (final double value in values) { - stddev += (value - mean) * (value - mean); - } - return math.sqrt(stddev / values.length); -} - -double _doIntegral({ - required double Function(double) func, - required double start, - required double stop, - required double resolution, -}) { - double result = 0.0; - while (start < stop) { - final double value = func(start); - result += resolution * value; - start += resolution; - } - return result; -} - -/// Probability is defined as the probability that the mean is within the -/// [margin] of the true value. -double _doProbability( - {required double mean, required double stddev, required double margin}) { - return _doIntegral( - func: (double x) => _doNormal(mean: mean, stddev: stddev, x: x), - start: (1.0 - margin) * mean, - stop: (1.0 + margin) * mean, - resolution: 0.001, - ); -} - -/// This class knows how to format benchmark results for machine and human -/// consumption. -/// - -/// Example: -/// -/// BenchmarkResultPrinter printer = BenchmarkResultPrinter(); -/// printer.add( -/// description: 'Average frame time', -/// value: averageFrameTime, -/// unit: 'ms', -/// name: 'average_frame_time', -/// ); -/// printer.printToStdout(); -/// -class BenchmarkResultPrinter { - final List<_BenchmarkResult> _results = <_BenchmarkResult>[]; - - /// Adds a benchmark result to the list of results. - /// - /// [description] is a human-readable description of the result. [value] is a - /// result value. [unit] is the unit of measurement, such as "ms", "km", "h". - /// [name] is a computer-readable name of the result used as a key in the JSON - /// serialization of the results. - void addResult( - {required String description, - required double value, - required String unit, - required String name}) { - _results.add(_BenchmarkResult(description, value, unit, name)); - } - - /// Adds a benchmark result to the list of results and a probability of that - /// result. - /// - /// The probability is calculated as the probability that the mean is +- 5% of - /// the true value. - /// - /// See also [addResult]. - void addResultStatistics({ - required String description, - required List values, - required String unit, - required String name, - }) { - final double mean = _doMean(values); - final double stddev = _doStddev(values, mean); - const double margin = 0.05; - final double probability = - _doProbability(mean: mean, stddev: stddev, margin: margin); - _results.add(_BenchmarkResult(description, mean, unit, name)); - _results.add(_BenchmarkResult( - '$description - probability margin of error $margin', - probability, - 'percent', - '${name}_probability_5pct')); - } - - /// Prints the results added via [addResult] to standard output, once as JSON - /// for computer consumption and once formatted as plain text for humans. - void printToStdout() { - // IMPORTANT: keep these values in sync with dev/devicelab/bin/tasks/microbenchmarks.dart - const String jsonStart = '================ RESULTS ================'; - const String jsonEnd = '================ FORMATTED =============='; - const String jsonPrefix = ':::JSON:::'; - - print(jsonStart); - print('$jsonPrefix ${_printJson()}'); - print(jsonEnd); - print(_printPlainText()); - } - - String _printJson() { - final Map results = {}; - for (final _BenchmarkResult result in _results) { - results[result.name] = result.value; - } - return json.encode(results); - } - - String _printPlainText() { - final StringBuffer buf = StringBuffer(); - for (final _BenchmarkResult result in _results) { - buf.writeln( - '${result.description}: ${result.value.toStringAsFixed(1)} ${result.unit}'); - } - return buf.toString(); - } -} - -class _BenchmarkResult { - _BenchmarkResult(this.description, this.value, this.unit, this.name); - - /// Human-readable description of the result, e.g. "Average frame time". - final String description; - - /// Result value that in agreement with [unit]. - final double value; - - /// Unit of measurement that is in agreement with [value]. - final String unit; - - /// Computer-readable name of the result. - final String name; -} diff --git a/benchmarks/lib/context.dart b/benchmarks/lib/context.dart deleted file mode 100644 index fc49b8b2b..000000000 --- a/benchmarks/lib/context.dart +++ /dev/null @@ -1,56 +0,0 @@ -import 'package:benchmarks/common.dart'; -import 'package:flutter/material.dart'; -// ignore: depend_on_referenced_packages -import 'package:flutter_test/flutter_test.dart'; -import 'package:mix/mix.dart'; -import 'package:mockito/mockito.dart'; - -class MockBuildContext extends Mock implements BuildContext {} - -/// flutter run -t lib/context.dart --release -void main() async { - assert( - false, - "Don't run benchmarks in debug mode! Use 'flutter run --release'.", - ); - - final printer = BenchmarkResultPrinter(); - final watch = Stopwatch(); - - testWidgets('Build', (tester) async { - await tester.pumpWidget(MaterialApp( - home: Builder(builder: (context) { - final expensiveContextMix = StyleMix( - onNot(onHover)(padding(10)), - onNot(onPress)(padding(15)), - onNot(onFocus)(padding(20)), - onNot(onDisabled)(padding(25)), - onDark(padding(30)), - onPortrait(padding(35)), - onMedium(padding(40)), - onSmall(padding(45)), - onLight(padding(50)), - onXSmall(padding(55)), - onLarge(padding(60)), - onPortrait(padding(65)), - ); - - watch.start(); - - MixData.create(context: context, style: expensiveContextMix); - - watch.stop(); - - printer.addResult( - description: 'Build an expensive context mix', - value: watch.elapsedMicroseconds.toDouble(), - unit: 'microseconds', - name: 'build_mix_context_bench', - ); - printer.printToStdout(); - - return Placeholder(); - }), - )); - }); -} diff --git a/benchmarks/lib/factoring.dart b/benchmarks/lib/factoring.dart deleted file mode 100644 index e8f9363d4..000000000 --- a/benchmarks/lib/factoring.dart +++ /dev/null @@ -1,141 +0,0 @@ -import 'package:benchmarks/common.dart'; -import 'package:flutter/material.dart'; -import 'package:mix/mix.dart'; - -/// flutter run -t lib/factoring.dart --release -void main() { - assert( - false, - "Don't run benchmarks in debug mode! Use 'flutter run --release'.", - ); - - final printer = BenchmarkResultPrinter(); - final watch = Stopwatch(); - - { - final firstMix = StyleMix( - height(100), - animation(), - marginVertical(10), - rounded(10), - backgroundColor(Color(0xFF00FF80)), - textStyle(as: TextStyle(), color: Color(0xFFFFFFFF)), - onHover( - padding(20), - backgroundColor(Color(0xFFFFFF80)), - textStyle(color: Color(0xFF000000)), - ), - ); - - final secondMix = StyleMix( - width(100), - marginHorizontal(10), - shadow(spreadRadius: 100), - rounded(100), - backgroundColor(Color(0xFF00FF80)), - border(color: Color(0xFF984F9B)), - onPress( - shadow(spreadRadius: 2), - margin(20), - backgroundColor(Color(0xFFFFFF80)), - textStyle(color: Color(0xFF000000)), - ), - ); - - watch.start(); - - StyleMix.combine([firstMix, secondMix]); - - watch.stop(); - - printer.addResult( - description: 'Combine two extense mixes', - value: watch.elapsedMicroseconds.toDouble(), - unit: 'microseconds', - name: 'combine_mix_bench', - ); - } - - watch.reset(); - - { - watch.start(); - - StyleMix.combine([ - StyleMix(backgroundColor(Colors.black)), - StyleMix(textStyle(color: Colors.black)), - StyleMix(margin(20)), - StyleMix(rounded(10)), - StyleMix(border(color: Colors.black)), - ]); - - watch.stop(); - - printer.addResult( - description: 'Combine multiple mixes', - value: watch.elapsedMicroseconds.toDouble(), - unit: 'microseconds', - name: 'combine_multiple_mixes_bench', - ); - } - - watch.reset(); - - { - final hasError = StyleVariant('hasError'); - final mix = StyleMix( - hasError( - padding(20), - backgroundColor(Color(0xFFFFFF80)), - textStyle(color: Color(0xFF000000)), - ), - ); - - watch.start(); - - mix.selectVariant(hasError); - - watch.stop(); - - printer.addResult( - description: 'Apply a variant to a mix', - value: watch.elapsedMicroseconds.toDouble(), - unit: 'microseconds', - name: 'apply_variant_bench', - ); - } - - watch.reset(); - - { - final mix = StyleMix( - onDisabled(padding(20)), - onFocus(backgroundColor(Color(0xFFFFFF80))), - onHover(textStyle(color: Color(0xFF000000))), - onPress(textStyle(backgroundColor: Color(0xFF964234))), - onDark(textStyle(height: 10)), - onLight(textStyle(shadow: Shadow(color: Color(0xFF000000)))), - ); - - watch.start(); - - mix.selectVariants([ - onDisabled, - onFocus, - onHover, - onPress, - onDark, - onLight, - ]); - - watch.stop(); - - printer.addResult( - description: 'Apply multiple variants to a mix', - value: watch.elapsedMicroseconds.toDouble(), - unit: 'microseconds', - name: 'apply_multiple_variants_bench', - ); - } - printer.printToStdout(); -} diff --git a/benchmarks/lib/main.dart b/benchmarks/lib/main.dart deleted file mode 100644 index 220224a39..000000000 --- a/benchmarks/lib/main.dart +++ /dev/null @@ -1,10 +0,0 @@ -import 'context.dart' as context_bench; -import 'factoring.dart' as factoring_bench; -import 'values.dart' as values_bench; - -/// flutter run -d windows --release -void main() { - context_bench.main(); - factoring_bench.main(); - values_bench.main(); -} diff --git a/benchmarks/lib/values.dart b/benchmarks/lib/values.dart deleted file mode 100644 index e1bb079d3..000000000 --- a/benchmarks/lib/values.dart +++ /dev/null @@ -1,40 +0,0 @@ -import 'package:benchmarks/common.dart'; -import 'package:flutter/material.dart'; -// ignore: depend_on_referenced_packages -import 'package:mix/mix.dart'; -import 'package:mockito/mockito.dart'; - -class MockBuildContext extends Mock implements BuildContext {} - -/// flutter run -t lib/values.dart --release -void main() async { - assert( - false, - "Don't run benchmarks in debug mode! Use 'flutter run --release'.", - ); - - final printer = BenchmarkResultPrinter(); - final watch = Stopwatch(); - - { - watch.start(); - - final variant = StyleVariant('light'); - StyleMix.fromValues(StyleMixData.create([ - backgroundColor(Color(0xFFFFFFFFF)), // directive - variant(textStyle(backgroundColor: Color(0xFF000000))), // variant - onHover(textStyle(color: Color(0xFF645876))), // context - scale(2.0), // decorator - ])); - - watch.stop(); - - printer.addResult( - description: 'Create a Mix from values', - value: watch.elapsedMicroseconds.toDouble(), - unit: 'microseconds', - name: 'create_mix_from_values_bench', - ); - } - printer.printToStdout(); -} diff --git a/benchmarks/linux/.gitignore b/benchmarks/linux/.gitignore deleted file mode 100644 index d3896c984..000000000 --- a/benchmarks/linux/.gitignore +++ /dev/null @@ -1 +0,0 @@ -flutter/ephemeral diff --git a/benchmarks/linux/CMakeLists.txt b/benchmarks/linux/CMakeLists.txt deleted file mode 100644 index 703acf9e1..000000000 --- a/benchmarks/linux/CMakeLists.txt +++ /dev/null @@ -1,138 +0,0 @@ -# Project-level configuration. -cmake_minimum_required(VERSION 3.10) -project(runner LANGUAGES CXX) - -# The name of the executable created for the application. Change this to change -# the on-disk name of your application. -set(BINARY_NAME "benchmarks") -# The unique GTK application identifier for this application. See: -# https://wiki.gnome.org/HowDoI/ChooseApplicationID -set(APPLICATION_ID "com.example.benchmarks") - -# Explicitly opt in to modern CMake behaviors to avoid warnings with recent -# versions of CMake. -cmake_policy(SET CMP0063 NEW) - -# Load bundled libraries from the lib/ directory relative to the binary. -set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") - -# Root filesystem for cross-building. -if(FLUTTER_TARGET_PLATFORM_SYSROOT) - set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) - set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) - set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) - set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) - set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) - set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) -endif() - -# Define build configuration options. -if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - set(CMAKE_BUILD_TYPE "Debug" CACHE - STRING "Flutter build mode" FORCE) - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS - "Debug" "Profile" "Release") -endif() - -# Compilation settings that should be applied to most targets. -# -# Be cautious about adding new options here, as plugins use this function by -# default. In most cases, you should add new options to specific targets instead -# of modifying this function. -function(APPLY_STANDARD_SETTINGS TARGET) - target_compile_features(${TARGET} PUBLIC cxx_std_14) - target_compile_options(${TARGET} PRIVATE -Wall -Werror) - target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") - target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") -endfunction() - -# Flutter library and tool build rules. -set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") -add_subdirectory(${FLUTTER_MANAGED_DIR}) - -# System-level dependencies. -find_package(PkgConfig REQUIRED) -pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) - -add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") - -# Define the application target. To change its name, change BINARY_NAME above, -# not the value here, or `flutter run` will no longer work. -# -# Any new source files that you add to the application should be added here. -add_executable(${BINARY_NAME} - "main.cc" - "my_application.cc" - "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" -) - -# Apply the standard set of build settings. This can be removed for applications -# that need different build settings. -apply_standard_settings(${BINARY_NAME}) - -# Add dependency libraries. Add any application-specific dependencies here. -target_link_libraries(${BINARY_NAME} PRIVATE flutter) -target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) - -# Run the Flutter tool portions of the build. This must not be removed. -add_dependencies(${BINARY_NAME} flutter_assemble) - -# Only the install-generated bundle's copy of the executable will launch -# correctly, since the resources must in the right relative locations. To avoid -# people trying to run the unbundled copy, put it in a subdirectory instead of -# the default top-level location. -set_target_properties(${BINARY_NAME} - PROPERTIES - RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" -) - -# Generated plugin build rules, which manage building the plugins and adding -# them to the application. -include(flutter/generated_plugins.cmake) - - -# === Installation === -# By default, "installing" just makes a relocatable bundle in the build -# directory. -set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") -if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) -endif() - -# Start with a clean build bundle directory every time. -install(CODE " - file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") - " COMPONENT Runtime) - -set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") -set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") - -install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" - COMPONENT Runtime) - -install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" - COMPONENT Runtime) - -install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) - -foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) - install(FILES "${bundled_library}" - DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) -endforeach(bundled_library) - -# Fully re-copy the assets directory on each build to avoid having stale files -# from a previous install. -set(FLUTTER_ASSET_DIR_NAME "flutter_assets") -install(CODE " - file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") - " COMPONENT Runtime) -install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" - DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) - -# Install the AOT library on non-Debug builds only. -if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") - install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) -endif() diff --git a/benchmarks/linux/flutter/CMakeLists.txt b/benchmarks/linux/flutter/CMakeLists.txt deleted file mode 100644 index d5bd01648..000000000 --- a/benchmarks/linux/flutter/CMakeLists.txt +++ /dev/null @@ -1,88 +0,0 @@ -# This file controls Flutter-level build steps. It should not be edited. -cmake_minimum_required(VERSION 3.10) - -set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") - -# Configuration provided via flutter tool. -include(${EPHEMERAL_DIR}/generated_config.cmake) - -# TODO: Move the rest of this into files in ephemeral. See -# https://github.com/flutter/flutter/issues/57146. - -# Serves the same purpose as list(TRANSFORM ... PREPEND ...), -# which isn't available in 3.10. -function(list_prepend LIST_NAME PREFIX) - set(NEW_LIST "") - foreach(element ${${LIST_NAME}}) - list(APPEND NEW_LIST "${PREFIX}${element}") - endforeach(element) - set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) -endfunction() - -# === Flutter Library === -# System-level dependencies. -find_package(PkgConfig REQUIRED) -pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) -pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) -pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) - -set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") - -# Published to parent scope for install step. -set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) -set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) -set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) -set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) - -list(APPEND FLUTTER_LIBRARY_HEADERS - "fl_basic_message_channel.h" - "fl_binary_codec.h" - "fl_binary_messenger.h" - "fl_dart_project.h" - "fl_engine.h" - "fl_json_message_codec.h" - "fl_json_method_codec.h" - "fl_message_codec.h" - "fl_method_call.h" - "fl_method_channel.h" - "fl_method_codec.h" - "fl_method_response.h" - "fl_plugin_registrar.h" - "fl_plugin_registry.h" - "fl_standard_message_codec.h" - "fl_standard_method_codec.h" - "fl_string_codec.h" - "fl_value.h" - "fl_view.h" - "flutter_linux.h" -) -list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") -add_library(flutter INTERFACE) -target_include_directories(flutter INTERFACE - "${EPHEMERAL_DIR}" -) -target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") -target_link_libraries(flutter INTERFACE - PkgConfig::GTK - PkgConfig::GLIB - PkgConfig::GIO -) -add_dependencies(flutter flutter_assemble) - -# === Flutter tool backend === -# _phony_ is a non-existent file to force this command to run every time, -# since currently there's no way to get a full input/output list from the -# flutter tool. -add_custom_command( - OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} - ${CMAKE_CURRENT_BINARY_DIR}/_phony_ - COMMAND ${CMAKE_COMMAND} -E env - ${FLUTTER_TOOL_ENVIRONMENT} - "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" - ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} - VERBATIM -) -add_custom_target(flutter_assemble DEPENDS - "${FLUTTER_LIBRARY}" - ${FLUTTER_LIBRARY_HEADERS} -) diff --git a/benchmarks/linux/flutter/generated_plugin_registrant.cc b/benchmarks/linux/flutter/generated_plugin_registrant.cc deleted file mode 100644 index e71a16d23..000000000 --- a/benchmarks/linux/flutter/generated_plugin_registrant.cc +++ /dev/null @@ -1,11 +0,0 @@ -// -// Generated file. Do not edit. -// - -// clang-format off - -#include "generated_plugin_registrant.h" - - -void fl_register_plugins(FlPluginRegistry* registry) { -} diff --git a/benchmarks/linux/flutter/generated_plugin_registrant.h b/benchmarks/linux/flutter/generated_plugin_registrant.h deleted file mode 100644 index e0f0a47bc..000000000 --- a/benchmarks/linux/flutter/generated_plugin_registrant.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// Generated file. Do not edit. -// - -// clang-format off - -#ifndef GENERATED_PLUGIN_REGISTRANT_ -#define GENERATED_PLUGIN_REGISTRANT_ - -#include - -// Registers Flutter plugins. -void fl_register_plugins(FlPluginRegistry* registry); - -#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/benchmarks/linux/flutter/generated_plugins.cmake b/benchmarks/linux/flutter/generated_plugins.cmake deleted file mode 100644 index 2e1de87a7..000000000 --- a/benchmarks/linux/flutter/generated_plugins.cmake +++ /dev/null @@ -1,23 +0,0 @@ -# -# Generated file, do not edit. -# - -list(APPEND FLUTTER_PLUGIN_LIST -) - -list(APPEND FLUTTER_FFI_PLUGIN_LIST -) - -set(PLUGIN_BUNDLED_LIBRARIES) - -foreach(plugin ${FLUTTER_PLUGIN_LIST}) - add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) - target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) - list(APPEND PLUGIN_BUNDLED_LIBRARIES $) - list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) -endforeach(plugin) - -foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) - add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) - list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) -endforeach(ffi_plugin) diff --git a/benchmarks/linux/main.cc b/benchmarks/linux/main.cc deleted file mode 100644 index e7c5c5437..000000000 --- a/benchmarks/linux/main.cc +++ /dev/null @@ -1,6 +0,0 @@ -#include "my_application.h" - -int main(int argc, char** argv) { - g_autoptr(MyApplication) app = my_application_new(); - return g_application_run(G_APPLICATION(app), argc, argv); -} diff --git a/benchmarks/linux/my_application.cc b/benchmarks/linux/my_application.cc deleted file mode 100644 index 8db2964fb..000000000 --- a/benchmarks/linux/my_application.cc +++ /dev/null @@ -1,104 +0,0 @@ -#include "my_application.h" - -#include -#ifdef GDK_WINDOWING_X11 -#include -#endif - -#include "flutter/generated_plugin_registrant.h" - -struct _MyApplication { - GtkApplication parent_instance; - char** dart_entrypoint_arguments; -}; - -G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) - -// Implements GApplication::activate. -static void my_application_activate(GApplication* application) { - MyApplication* self = MY_APPLICATION(application); - GtkWindow* window = - GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); - - // Use a header bar when running in GNOME as this is the common style used - // by applications and is the setup most users will be using (e.g. Ubuntu - // desktop). - // If running on X and not using GNOME then just use a traditional title bar - // in case the window manager does more exotic layout, e.g. tiling. - // If running on Wayland assume the header bar will work (may need changing - // if future cases occur). - gboolean use_header_bar = TRUE; -#ifdef GDK_WINDOWING_X11 - GdkScreen* screen = gtk_window_get_screen(window); - if (GDK_IS_X11_SCREEN(screen)) { - const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); - if (g_strcmp0(wm_name, "GNOME Shell") != 0) { - use_header_bar = FALSE; - } - } -#endif - if (use_header_bar) { - GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); - gtk_widget_show(GTK_WIDGET(header_bar)); - gtk_header_bar_set_title(header_bar, "benchmarks"); - gtk_header_bar_set_show_close_button(header_bar, TRUE); - gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); - } else { - gtk_window_set_title(window, "benchmarks"); - } - - gtk_window_set_default_size(window, 1280, 720); - gtk_widget_show(GTK_WIDGET(window)); - - g_autoptr(FlDartProject) project = fl_dart_project_new(); - fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); - - FlView* view = fl_view_new(project); - gtk_widget_show(GTK_WIDGET(view)); - gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); - - fl_register_plugins(FL_PLUGIN_REGISTRY(view)); - - gtk_widget_grab_focus(GTK_WIDGET(view)); -} - -// Implements GApplication::local_command_line. -static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { - MyApplication* self = MY_APPLICATION(application); - // Strip out the first argument as it is the binary name. - self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); - - g_autoptr(GError) error = nullptr; - if (!g_application_register(application, nullptr, &error)) { - g_warning("Failed to register: %s", error->message); - *exit_status = 1; - return TRUE; - } - - g_application_activate(application); - *exit_status = 0; - - return TRUE; -} - -// Implements GObject::dispose. -static void my_application_dispose(GObject* object) { - MyApplication* self = MY_APPLICATION(object); - g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); - G_OBJECT_CLASS(my_application_parent_class)->dispose(object); -} - -static void my_application_class_init(MyApplicationClass* klass) { - G_APPLICATION_CLASS(klass)->activate = my_application_activate; - G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; - G_OBJECT_CLASS(klass)->dispose = my_application_dispose; -} - -static void my_application_init(MyApplication* self) {} - -MyApplication* my_application_new() { - return MY_APPLICATION(g_object_new(my_application_get_type(), - "application-id", APPLICATION_ID, - "flags", G_APPLICATION_NON_UNIQUE, - nullptr)); -} diff --git a/benchmarks/linux/my_application.h b/benchmarks/linux/my_application.h deleted file mode 100644 index 72271d5e4..000000000 --- a/benchmarks/linux/my_application.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef FLUTTER_MY_APPLICATION_H_ -#define FLUTTER_MY_APPLICATION_H_ - -#include - -G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, - GtkApplication) - -/** - * my_application_new: - * - * Creates a new Flutter-based application. - * - * Returns: a new #MyApplication. - */ -MyApplication* my_application_new(); - -#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/benchmarks/macos/.gitignore b/benchmarks/macos/.gitignore deleted file mode 100644 index 746adbb6b..000000000 --- a/benchmarks/macos/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -# Flutter-related -**/Flutter/ephemeral/ -**/Pods/ - -# Xcode-related -**/dgph -**/xcuserdata/ diff --git a/benchmarks/macos/Flutter/Flutter-Debug.xcconfig b/benchmarks/macos/Flutter/Flutter-Debug.xcconfig deleted file mode 100644 index c2efd0b60..000000000 --- a/benchmarks/macos/Flutter/Flutter-Debug.xcconfig +++ /dev/null @@ -1 +0,0 @@ -#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/benchmarks/macos/Flutter/Flutter-Release.xcconfig b/benchmarks/macos/Flutter/Flutter-Release.xcconfig deleted file mode 100644 index c2efd0b60..000000000 --- a/benchmarks/macos/Flutter/Flutter-Release.xcconfig +++ /dev/null @@ -1 +0,0 @@ -#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/benchmarks/macos/Flutter/GeneratedPluginRegistrant.swift b/benchmarks/macos/Flutter/GeneratedPluginRegistrant.swift deleted file mode 100644 index cccf817a5..000000000 --- a/benchmarks/macos/Flutter/GeneratedPluginRegistrant.swift +++ /dev/null @@ -1,10 +0,0 @@ -// -// Generated file. Do not edit. -// - -import FlutterMacOS -import Foundation - - -func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { -} diff --git a/benchmarks/macos/Runner.xcodeproj/project.pbxproj b/benchmarks/macos/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index 8dda5a554..000000000 --- a/benchmarks/macos/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,573 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 54; - objects = { - -/* Begin PBXAggregateTarget section */ - 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { - isa = PBXAggregateTarget; - buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; - buildPhases = ( - 33CC111E2044C6BF0003C045 /* ShellScript */, - ); - dependencies = ( - ); - name = "Flutter Assemble"; - productName = FLX; - }; -/* End PBXAggregateTarget section */ - -/* Begin PBXBuildFile section */ - 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; - 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; - 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; - 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; - 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 33CC10E52044A3C60003C045 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 33CC111A2044C6BA0003C045; - remoteInfo = FLX; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 33CC110E2044A8840003C045 /* Bundle Framework */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - ); - name = "Bundle Framework"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; - 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; - 33CC10ED2044A3C60003C045 /* benchmarks.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "benchmarks.app"; sourceTree = BUILT_PRODUCTS_DIR; }; - 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; - 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; - 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; - 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; - 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; - 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; - 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; - 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; - 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; - 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 33CC10EA2044A3C60003C045 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 33BA886A226E78AF003329D5 /* Configs */ = { - isa = PBXGroup; - children = ( - 33E5194F232828860026EE4D /* AppInfo.xcconfig */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, - ); - path = Configs; - sourceTree = ""; - }; - 33CC10E42044A3C60003C045 = { - isa = PBXGroup; - children = ( - 33FAB671232836740065AC1E /* Runner */, - 33CEB47122A05771004F2AC0 /* Flutter */, - 33CC10EE2044A3C60003C045 /* Products */, - D73912EC22F37F3D000D13A0 /* Frameworks */, - ); - sourceTree = ""; - }; - 33CC10EE2044A3C60003C045 /* Products */ = { - isa = PBXGroup; - children = ( - 33CC10ED2044A3C60003C045 /* benchmarks.app */, - ); - name = Products; - sourceTree = ""; - }; - 33CC11242044D66E0003C045 /* Resources */ = { - isa = PBXGroup; - children = ( - 33CC10F22044A3C60003C045 /* Assets.xcassets */, - 33CC10F42044A3C60003C045 /* MainMenu.xib */, - 33CC10F72044A3C60003C045 /* Info.plist */, - ); - name = Resources; - path = ..; - sourceTree = ""; - }; - 33CEB47122A05771004F2AC0 /* Flutter */ = { - isa = PBXGroup; - children = ( - 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, - 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, - 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, - 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, - ); - path = Flutter; - sourceTree = ""; - }; - 33FAB671232836740065AC1E /* Runner */ = { - isa = PBXGroup; - children = ( - 33CC10F02044A3C60003C045 /* AppDelegate.swift */, - 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, - 33E51913231747F40026EE4D /* DebugProfile.entitlements */, - 33E51914231749380026EE4D /* Release.entitlements */, - 33CC11242044D66E0003C045 /* Resources */, - 33BA886A226E78AF003329D5 /* Configs */, - ); - path = Runner; - sourceTree = ""; - }; - D73912EC22F37F3D000D13A0 /* Frameworks */ = { - isa = PBXGroup; - children = ( - ); - name = Frameworks; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 33CC10EC2044A3C60003C045 /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - 33CC10E92044A3C60003C045 /* Sources */, - 33CC10EA2044A3C60003C045 /* Frameworks */, - 33CC10EB2044A3C60003C045 /* Resources */, - 33CC110E2044A8840003C045 /* Bundle Framework */, - 3399D490228B24CF009A79C7 /* ShellScript */, - ); - buildRules = ( - ); - dependencies = ( - 33CC11202044C79F0003C045 /* PBXTargetDependency */, - ); - name = Runner; - productName = Runner; - productReference = 33CC10ED2044A3C60003C045 /* benchmarks.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 33CC10E52044A3C60003C045 /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 1300; - ORGANIZATIONNAME = ""; - TargetAttributes = { - 33CC10EC2044A3C60003C045 = { - CreatedOnToolsVersion = 9.2; - LastSwiftMigration = 1100; - ProvisioningStyle = Automatic; - SystemCapabilities = { - com.apple.Sandbox = { - enabled = 1; - }; - }; - }; - 33CC111A2044C6BA0003C045 = { - CreatedOnToolsVersion = 9.2; - ProvisioningStyle = Manual; - }; - }; - }; - buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 9.3"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 33CC10E42044A3C60003C045; - productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 33CC10EC2044A3C60003C045 /* Runner */, - 33CC111A2044C6BA0003C045 /* Flutter Assemble */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 33CC10EB2044A3C60003C045 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, - 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 3399D490228B24CF009A79C7 /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; - }; - 33CC111E2044C6BF0003C045 /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - Flutter/ephemeral/FlutterInputs.xcfilelist, - ); - inputPaths = ( - Flutter/ephemeral/tripwire, - ); - outputFileListPaths = ( - Flutter/ephemeral/FlutterOutputs.xcfilelist, - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 33CC10E92044A3C60003C045 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, - 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, - 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; - targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { - isa = PBXVariantGroup; - children = ( - 33CC10F52044A3C60003C045 /* Base */, - ); - name = MainMenu.xib; - path = Runner; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 338D0CE9231458BD00FA5F75 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.14; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = macosx; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - }; - name = Profile; - }; - 338D0CEA231458BD00FA5F75 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_VERSION = 5.0; - }; - name = Profile; - }; - 338D0CEB231458BD00FA5F75 /* Profile */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Manual; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Profile; - }; - 33CC10F92044A3C60003C045 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.14; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = macosx; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - }; - name = Debug; - }; - 33CC10FA2044A3C60003C045 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.14; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = macosx; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - }; - name = Release; - }; - 33CC10FC2044A3C60003C045 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - }; - name = Debug; - }; - 33CC10FD2044A3C60003C045 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_VERSION = 5.0; - }; - name = Release; - }; - 33CC111C2044C6BA0003C045 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Manual; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 33CC111D2044C6BA0003C045 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 33CC10F92044A3C60003C045 /* Debug */, - 33CC10FA2044A3C60003C045 /* Release */, - 338D0CE9231458BD00FA5F75 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 33CC10FC2044A3C60003C045 /* Debug */, - 33CC10FD2044A3C60003C045 /* Release */, - 338D0CEA231458BD00FA5F75 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 33CC111C2044C6BA0003C045 /* Debug */, - 33CC111D2044C6BA0003C045 /* Release */, - 338D0CEB231458BD00FA5F75 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 33CC10E52044A3C60003C045 /* Project object */; -} diff --git a/benchmarks/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/benchmarks/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003..000000000 --- a/benchmarks/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/benchmarks/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/benchmarks/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100644 index 9a04e11d4..000000000 --- a/benchmarks/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/benchmarks/macos/Runner.xcworkspace/contents.xcworkspacedata b/benchmarks/macos/Runner.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 1d526a16e..000000000 --- a/benchmarks/macos/Runner.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/benchmarks/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/benchmarks/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003..000000000 --- a/benchmarks/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/benchmarks/macos/Runner/AppDelegate.swift b/benchmarks/macos/Runner/AppDelegate.swift deleted file mode 100644 index d53ef6437..000000000 --- a/benchmarks/macos/Runner/AppDelegate.swift +++ /dev/null @@ -1,9 +0,0 @@ -import Cocoa -import FlutterMacOS - -@NSApplicationMain -class AppDelegate: FlutterAppDelegate { - override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { - return true - } -} diff --git a/benchmarks/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/benchmarks/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index a2ec33f19..000000000 --- a/benchmarks/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "images" : [ - { - "size" : "16x16", - "idiom" : "mac", - "filename" : "app_icon_16.png", - "scale" : "1x" - }, - { - "size" : "16x16", - "idiom" : "mac", - "filename" : "app_icon_32.png", - "scale" : "2x" - }, - { - "size" : "32x32", - "idiom" : "mac", - "filename" : "app_icon_32.png", - "scale" : "1x" - }, - { - "size" : "32x32", - "idiom" : "mac", - "filename" : "app_icon_64.png", - "scale" : "2x" - }, - { - "size" : "128x128", - "idiom" : "mac", - "filename" : "app_icon_128.png", - "scale" : "1x" - }, - { - "size" : "128x128", - "idiom" : "mac", - "filename" : "app_icon_256.png", - "scale" : "2x" - }, - { - "size" : "256x256", - "idiom" : "mac", - "filename" : "app_icon_256.png", - "scale" : "1x" - }, - { - "size" : "256x256", - "idiom" : "mac", - "filename" : "app_icon_512.png", - "scale" : "2x" - }, - { - "size" : "512x512", - "idiom" : "mac", - "filename" : "app_icon_512.png", - "scale" : "1x" - }, - { - "size" : "512x512", - "idiom" : "mac", - "filename" : "app_icon_1024.png", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/benchmarks/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/benchmarks/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png deleted file mode 100644 index 82b6f9d9a..000000000 Binary files a/benchmarks/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png and /dev/null differ diff --git a/benchmarks/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/benchmarks/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png deleted file mode 100644 index 13b35eba5..000000000 Binary files a/benchmarks/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png and /dev/null differ diff --git a/benchmarks/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/benchmarks/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png deleted file mode 100644 index 0a3f5fa40..000000000 Binary files a/benchmarks/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png and /dev/null differ diff --git a/benchmarks/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/benchmarks/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png deleted file mode 100644 index bdb57226d..000000000 Binary files a/benchmarks/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png and /dev/null differ diff --git a/benchmarks/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/benchmarks/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png deleted file mode 100644 index f083318e0..000000000 Binary files a/benchmarks/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png and /dev/null differ diff --git a/benchmarks/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/benchmarks/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png deleted file mode 100644 index 326c0e72c..000000000 Binary files a/benchmarks/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png and /dev/null differ diff --git a/benchmarks/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/benchmarks/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png deleted file mode 100644 index 2f1632cfd..000000000 Binary files a/benchmarks/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png and /dev/null differ diff --git a/benchmarks/macos/Runner/Base.lproj/MainMenu.xib b/benchmarks/macos/Runner/Base.lproj/MainMenu.xib deleted file mode 100644 index 80e867a4e..000000000 --- a/benchmarks/macos/Runner/Base.lproj/MainMenu.xib +++ /dev/null @@ -1,343 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/benchmarks/macos/Runner/Configs/AppInfo.xcconfig b/benchmarks/macos/Runner/Configs/AppInfo.xcconfig deleted file mode 100644 index 2f0c402ea..000000000 --- a/benchmarks/macos/Runner/Configs/AppInfo.xcconfig +++ /dev/null @@ -1,14 +0,0 @@ -// Application-level settings for the Runner target. -// -// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the -// future. If not, the values below would default to using the project name when this becomes a -// 'flutter create' template. - -// The application's name. By default this is also the title of the Flutter window. -PRODUCT_NAME = benchmarks - -// The application's bundle identifier -PRODUCT_BUNDLE_IDENTIFIER = com.example.benchmarks - -// The copyright displayed in application information -PRODUCT_COPYRIGHT = Copyright © 2022 com.example. All rights reserved. diff --git a/benchmarks/macos/Runner/Configs/Debug.xcconfig b/benchmarks/macos/Runner/Configs/Debug.xcconfig deleted file mode 100644 index 36b0fd946..000000000 --- a/benchmarks/macos/Runner/Configs/Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "../../Flutter/Flutter-Debug.xcconfig" -#include "Warnings.xcconfig" diff --git a/benchmarks/macos/Runner/Configs/Release.xcconfig b/benchmarks/macos/Runner/Configs/Release.xcconfig deleted file mode 100644 index dff4f4956..000000000 --- a/benchmarks/macos/Runner/Configs/Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "../../Flutter/Flutter-Release.xcconfig" -#include "Warnings.xcconfig" diff --git a/benchmarks/macos/Runner/Configs/Warnings.xcconfig b/benchmarks/macos/Runner/Configs/Warnings.xcconfig deleted file mode 100644 index 42bcbf478..000000000 --- a/benchmarks/macos/Runner/Configs/Warnings.xcconfig +++ /dev/null @@ -1,13 +0,0 @@ -WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings -GCC_WARN_UNDECLARED_SELECTOR = YES -CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES -CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE -CLANG_WARN__DUPLICATE_METHOD_MATCH = YES -CLANG_WARN_PRAGMA_PACK = YES -CLANG_WARN_STRICT_PROTOTYPES = YES -CLANG_WARN_COMMA = YES -GCC_WARN_STRICT_SELECTOR_MATCH = YES -CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES -CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES -GCC_WARN_SHADOW = YES -CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/benchmarks/macos/Runner/DebugProfile.entitlements b/benchmarks/macos/Runner/DebugProfile.entitlements deleted file mode 100644 index dddb8a30c..000000000 --- a/benchmarks/macos/Runner/DebugProfile.entitlements +++ /dev/null @@ -1,12 +0,0 @@ - - - - - com.apple.security.app-sandbox - - com.apple.security.cs.allow-jit - - com.apple.security.network.server - - - diff --git a/benchmarks/macos/Runner/Info.plist b/benchmarks/macos/Runner/Info.plist deleted file mode 100644 index 4789daa6a..000000000 --- a/benchmarks/macos/Runner/Info.plist +++ /dev/null @@ -1,32 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIconFile - - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSMinimumSystemVersion - $(MACOSX_DEPLOYMENT_TARGET) - NSHumanReadableCopyright - $(PRODUCT_COPYRIGHT) - NSMainNibFile - MainMenu - NSPrincipalClass - NSApplication - - diff --git a/benchmarks/macos/Runner/MainFlutterWindow.swift b/benchmarks/macos/Runner/MainFlutterWindow.swift deleted file mode 100644 index 2722837ec..000000000 --- a/benchmarks/macos/Runner/MainFlutterWindow.swift +++ /dev/null @@ -1,15 +0,0 @@ -import Cocoa -import FlutterMacOS - -class MainFlutterWindow: NSWindow { - override func awakeFromNib() { - let flutterViewController = FlutterViewController.init() - let windowFrame = self.frame - self.contentViewController = flutterViewController - self.setFrame(windowFrame, display: true) - - RegisterGeneratedPlugins(registry: flutterViewController) - - super.awakeFromNib() - } -} diff --git a/benchmarks/macos/Runner/Release.entitlements b/benchmarks/macos/Runner/Release.entitlements deleted file mode 100644 index 852fa1a47..000000000 --- a/benchmarks/macos/Runner/Release.entitlements +++ /dev/null @@ -1,8 +0,0 @@ - - - - - com.apple.security.app-sandbox - - - diff --git a/benchmarks/pubspec.lock b/benchmarks/pubspec.lock deleted file mode 100644 index 58f2c5b55..000000000 --- a/benchmarks/pubspec.lock +++ /dev/null @@ -1,499 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - _fe_analyzer_shared: - dependency: transitive - description: - name: _fe_analyzer_shared - sha256: a36ec4843dc30ea6bf652bf25e3448db6c5e8bcf4aa55f063a5d1dad216d8214 - url: "https://pub.dev" - source: hosted - version: "58.0.0" - analyzer: - dependency: transitive - description: - name: analyzer - sha256: cc4242565347e98424ce9945c819c192ec0838cb9d1f6aa4a97cc96becbc5b27 - url: "https://pub.dev" - source: hosted - version: "5.10.0" - args: - dependency: transitive - description: - name: args - sha256: "4cab82a83ffef80b262ddedf47a0a8e56ee6fbf7fe21e6e768b02792034dd440" - url: "https://pub.dev" - source: hosted - version: "2.4.0" - async: - dependency: transitive - description: - name: async - sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" - url: "https://pub.dev" - source: hosted - version: "2.11.0" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - build: - dependency: transitive - description: - name: build - sha256: "3fbda25365741f8251b39f3917fb3c8e286a96fd068a5a242e11c2012d495777" - url: "https://pub.dev" - source: hosted - version: "2.3.1" - built_collection: - dependency: transitive - description: - name: built_collection - sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" - url: "https://pub.dev" - source: hosted - version: "5.1.1" - built_value: - dependency: transitive - description: - name: built_value - sha256: "31b7c748fd4b9adf8d25d72a4c4a59ef119f12876cf414f94f8af5131d5fa2b0" - url: "https://pub.dev" - source: hosted - version: "8.4.4" - characters: - dependency: transitive - description: - name: characters - sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" - url: "https://pub.dev" - source: hosted - version: "1.3.0" - clock: - dependency: transitive - description: - name: clock - sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf - url: "https://pub.dev" - source: hosted - version: "1.1.1" - code_builder: - dependency: transitive - description: - name: code_builder - sha256: "0d43dd1288fd145de1ecc9a3948ad4a6d5a82f0a14c4fdd0892260787d975cbe" - url: "https://pub.dev" - source: hosted - version: "4.4.0" - collection: - dependency: transitive - description: - name: collection - sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" - url: "https://pub.dev" - source: hosted - version: "1.17.1" - convert: - dependency: transitive - description: - name: convert - sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" - url: "https://pub.dev" - source: hosted - version: "3.1.1" - coverage: - dependency: transitive - description: - name: coverage - sha256: "2fb815080e44a09b85e0f2ca8a820b15053982b2e714b59267719e8a9ff17097" - url: "https://pub.dev" - source: hosted - version: "1.6.3" - crypto: - dependency: transitive - description: - name: crypto - sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 - url: "https://pub.dev" - source: hosted - version: "3.0.2" - dart_style: - dependency: transitive - description: - name: dart_style - sha256: "6d691edde054969f0e0f26abb1b30834b5138b963793e56f69d3a9a4435e6352" - url: "https://pub.dev" - source: hosted - version: "2.3.0" - fake_async: - dependency: transitive - description: - name: fake_async - sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" - url: "https://pub.dev" - source: hosted - version: "1.3.1" - file: - dependency: transitive - description: - name: file - sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" - url: "https://pub.dev" - source: hosted - version: "6.1.4" - fixnum: - dependency: transitive - description: - name: fixnum - sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" - url: "https://pub.dev" - source: hosted - version: "1.1.0" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - frontend_server_client: - dependency: transitive - description: - name: frontend_server_client - sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" - url: "https://pub.dev" - source: hosted - version: "3.2.0" - glob: - dependency: transitive - description: - name: glob - sha256: "4515b5b6ddb505ebdd242a5f2cc5d22d3d6a80013789debfbda7777f47ea308c" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - http_multi_server: - dependency: transitive - description: - name: http_multi_server - sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" - url: "https://pub.dev" - source: hosted - version: "3.2.1" - http_parser: - dependency: transitive - description: - name: http_parser - sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" - url: "https://pub.dev" - source: hosted - version: "4.0.2" - io: - dependency: transitive - description: - name: io - sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" - url: "https://pub.dev" - source: hosted - version: "1.0.4" - js: - dependency: transitive - description: - name: js - sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 - url: "https://pub.dev" - source: hosted - version: "0.6.7" - lints: - dependency: "direct dev" - description: - name: lints - sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593" - url: "https://pub.dev" - source: hosted - version: "2.0.1" - logging: - dependency: transitive - description: - name: logging - sha256: "04094f2eb032cbb06c6f6e8d3607edcfcb0455e2bb6cbc010cb01171dcb64e6d" - url: "https://pub.dev" - source: hosted - version: "1.1.1" - matcher: - dependency: transitive - description: - name: matcher - sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" - url: "https://pub.dev" - source: hosted - version: "0.12.15" - material_color_utilities: - dependency: transitive - description: - name: material_color_utilities - sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 - url: "https://pub.dev" - source: hosted - version: "0.2.0" - meta: - dependency: transitive - description: - name: meta - sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" - url: "https://pub.dev" - source: hosted - version: "1.9.1" - mime: - dependency: transitive - description: - name: mime - sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e - url: "https://pub.dev" - source: hosted - version: "1.0.4" - mix: - dependency: "direct main" - description: - path: ".." - relative: true - source: path - version: "0.0.7" - mockito: - dependency: "direct main" - description: - name: mockito - sha256: dd61809f04da1838a680926de50a9e87385c1de91c6579629c3d1723946e8059 - url: "https://pub.dev" - source: hosted - version: "5.4.0" - node_preamble: - dependency: transitive - description: - name: node_preamble - sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" - url: "https://pub.dev" - source: hosted - version: "2.0.2" - package_config: - dependency: transitive - description: - name: package_config - sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" - url: "https://pub.dev" - source: hosted - version: "2.1.0" - path: - dependency: transitive - description: - name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" - url: "https://pub.dev" - source: hosted - version: "1.8.3" - pool: - dependency: transitive - description: - name: pool - sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" - url: "https://pub.dev" - source: hosted - version: "1.5.1" - pub_semver: - dependency: transitive - description: - name: pub_semver - sha256: "307de764d305289ff24ad257ad5c5793ce56d04947599ad68b3baa124105fc17" - url: "https://pub.dev" - source: hosted - version: "2.1.3" - shelf: - dependency: transitive - description: - name: shelf - sha256: c24a96135a2ccd62c64b69315a14adc5c3419df63b4d7c05832a346fdb73682c - url: "https://pub.dev" - source: hosted - version: "1.4.0" - shelf_packages_handler: - dependency: transitive - description: - name: shelf_packages_handler - sha256: aef74dc9195746a384843102142ab65b6a4735bb3beea791e63527b88cc83306 - url: "https://pub.dev" - source: hosted - version: "3.0.1" - shelf_static: - dependency: transitive - description: - name: shelf_static - sha256: e792b76b96a36d4a41b819da593aff4bdd413576b3ba6150df5d8d9996d2e74c - url: "https://pub.dev" - source: hosted - version: "1.1.1" - shelf_web_socket: - dependency: transitive - description: - name: shelf_web_socket - sha256: a988c0e8d8ffbdb8a28aa7ec8e449c260f3deb808781fe1284d22c5bba7156e8 - url: "https://pub.dev" - source: hosted - version: "1.0.3" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.99" - source_gen: - dependency: transitive - description: - name: source_gen - sha256: c2bea18c95cfa0276a366270afaa2850b09b4a76db95d546f3d003dcc7011298 - url: "https://pub.dev" - source: hosted - version: "1.2.7" - source_map_stack_trace: - dependency: transitive - description: - name: source_map_stack_trace - sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - source_maps: - dependency: transitive - description: - name: source_maps - sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703" - url: "https://pub.dev" - source: hosted - version: "0.10.12" - source_span: - dependency: transitive - description: - name: source_span - sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 - url: "https://pub.dev" - source: hosted - version: "1.9.1" - stack_trace: - dependency: transitive - description: - name: stack_trace - sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 - url: "https://pub.dev" - source: hosted - version: "1.11.0" - stream_channel: - dependency: transitive - description: - name: stream_channel - sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - string_scanner: - dependency: transitive - description: - name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" - url: "https://pub.dev" - source: hosted - version: "1.2.0" - term_glyph: - dependency: transitive - description: - name: term_glyph - sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 - url: "https://pub.dev" - source: hosted - version: "1.2.1" - test: - dependency: "direct dev" - description: - name: test - sha256: "3dac9aecf2c3991d09b9cdde4f98ded7b30804a88a0d7e4e7e1678e78d6b97f4" - url: "https://pub.dev" - source: hosted - version: "1.24.1" - test_api: - dependency: transitive - description: - name: test_api - sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb - url: "https://pub.dev" - source: hosted - version: "0.5.1" - test_core: - dependency: transitive - description: - name: test_core - sha256: "5138dbffb77b2289ecb12b81c11ba46036590b72a64a7a90d6ffb880f1a29e93" - url: "https://pub.dev" - source: hosted - version: "0.5.1" - typed_data: - dependency: transitive - description: - name: typed_data - sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5" - url: "https://pub.dev" - source: hosted - version: "1.3.1" - vector_math: - dependency: transitive - description: - name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - vm_service: - dependency: transitive - description: - name: vm_service - sha256: e7fb6c2282f7631712b69c19d1bff82f3767eea33a2321c14fa59ad67ea391c7 - url: "https://pub.dev" - source: hosted - version: "9.4.0" - watcher: - dependency: transitive - description: - name: watcher - sha256: "6a7f46926b01ce81bfc339da6a7f20afbe7733eff9846f6d6a5466aa4c6667c0" - url: "https://pub.dev" - source: hosted - version: "1.0.2" - web_socket_channel: - dependency: transitive - description: - name: web_socket_channel - sha256: ca49c0bc209c687b887f30527fb6a9d80040b072cc2990f34b9bec3e7663101b - url: "https://pub.dev" - source: hosted - version: "2.3.0" - webkit_inspection_protocol: - dependency: transitive - description: - name: webkit_inspection_protocol - sha256: "67d3a8b6c79e1987d19d848b0892e582dbb0c66c57cc1fef58a177dd2aa2823d" - url: "https://pub.dev" - source: hosted - version: "1.2.0" - yaml: - dependency: transitive - description: - name: yaml - sha256: "23812a9b125b48d4007117254bca50abb6c712352927eece9e155207b1db2370" - url: "https://pub.dev" - source: hosted - version: "3.1.1" -sdks: - dart: ">=3.0.0-0 <4.0.0" diff --git a/benchmarks/pubspec.yaml b/benchmarks/pubspec.yaml deleted file mode 100644 index b5b8c8290..000000000 --- a/benchmarks/pubspec.yaml +++ /dev/null @@ -1,22 +0,0 @@ -name: benchmarks -description: A sample command-line application. -version: 1.0.0 - -environment: - sdk: '>=2.13.0 <3.0.0' - -dependencies: - flutter: - sdk: flutter - mix: - mockito: ^5.3.2 - -dev_dependencies: - flutter_test: - sdk: flutter - lints: ^2.0.0 - test: ^1.16.0 - -dependency_overrides: - mix: - path: ../ diff --git a/benchmarks/web/favicon.png b/benchmarks/web/favicon.png deleted file mode 100644 index 8aaa46ac1..000000000 Binary files a/benchmarks/web/favicon.png and /dev/null differ diff --git a/benchmarks/web/icons/Icon-192.png b/benchmarks/web/icons/Icon-192.png deleted file mode 100644 index b749bfef0..000000000 Binary files a/benchmarks/web/icons/Icon-192.png and /dev/null differ diff --git a/benchmarks/web/icons/Icon-512.png b/benchmarks/web/icons/Icon-512.png deleted file mode 100644 index 88cfd48df..000000000 Binary files a/benchmarks/web/icons/Icon-512.png and /dev/null differ diff --git a/benchmarks/web/icons/Icon-maskable-192.png b/benchmarks/web/icons/Icon-maskable-192.png deleted file mode 100644 index eb9b4d76e..000000000 Binary files a/benchmarks/web/icons/Icon-maskable-192.png and /dev/null differ diff --git a/benchmarks/web/icons/Icon-maskable-512.png b/benchmarks/web/icons/Icon-maskable-512.png deleted file mode 100644 index d69c56691..000000000 Binary files a/benchmarks/web/icons/Icon-maskable-512.png and /dev/null differ diff --git a/benchmarks/web/index.html b/benchmarks/web/index.html deleted file mode 100644 index 9ecc1915c..000000000 --- a/benchmarks/web/index.html +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - - - - - - - - benchmarks - - - - - - - - - - diff --git a/benchmarks/web/manifest.json b/benchmarks/web/manifest.json deleted file mode 100644 index b753ad081..000000000 --- a/benchmarks/web/manifest.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "benchmarks", - "short_name": "benchmarks", - "start_url": ".", - "display": "standalone", - "background_color": "#0175C2", - "theme_color": "#0175C2", - "description": "A new Flutter project.", - "orientation": "portrait-primary", - "prefer_related_applications": false, - "icons": [ - { - "src": "icons/Icon-192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "icons/Icon-512.png", - "sizes": "512x512", - "type": "image/png" - }, - { - "src": "icons/Icon-maskable-192.png", - "sizes": "192x192", - "type": "image/png", - "purpose": "maskable" - }, - { - "src": "icons/Icon-maskable-512.png", - "sizes": "512x512", - "type": "image/png", - "purpose": "maskable" - } - ] -} diff --git a/benchmarks/windows/.gitignore b/benchmarks/windows/.gitignore deleted file mode 100644 index d492d0d98..000000000 --- a/benchmarks/windows/.gitignore +++ /dev/null @@ -1,17 +0,0 @@ -flutter/ephemeral/ - -# Visual Studio user-specific files. -*.suo -*.user -*.userosscache -*.sln.docstates - -# Visual Studio build-related files. -x64/ -x86/ - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!*.[Cc]ache/ diff --git a/benchmarks/windows/CMakeLists.txt b/benchmarks/windows/CMakeLists.txt deleted file mode 100644 index 6d4062429..000000000 --- a/benchmarks/windows/CMakeLists.txt +++ /dev/null @@ -1,101 +0,0 @@ -# Project-level configuration. -cmake_minimum_required(VERSION 3.14) -project(benchmarks LANGUAGES CXX) - -# The name of the executable created for the application. Change this to change -# the on-disk name of your application. -set(BINARY_NAME "benchmarks") - -# Explicitly opt in to modern CMake behaviors to avoid warnings with recent -# versions of CMake. -cmake_policy(SET CMP0063 NEW) - -# Define build configuration option. -get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) -if(IS_MULTICONFIG) - set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" - CACHE STRING "" FORCE) -else() - if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - set(CMAKE_BUILD_TYPE "Debug" CACHE - STRING "Flutter build mode" FORCE) - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS - "Debug" "Profile" "Release") - endif() -endif() -# Define settings for the Profile build mode. -set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") -set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") -set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") -set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") - -# Use Unicode for all projects. -add_definitions(-DUNICODE -D_UNICODE) - -# Compilation settings that should be applied to most targets. -# -# Be cautious about adding new options here, as plugins use this function by -# default. In most cases, you should add new options to specific targets instead -# of modifying this function. -function(APPLY_STANDARD_SETTINGS TARGET) - target_compile_features(${TARGET} PUBLIC cxx_std_17) - target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") - target_compile_options(${TARGET} PRIVATE /EHsc) - target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") - target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") -endfunction() - -# Flutter library and tool build rules. -set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") -add_subdirectory(${FLUTTER_MANAGED_DIR}) - -# Application build; see runner/CMakeLists.txt. -add_subdirectory("runner") - -# Generated plugin build rules, which manage building the plugins and adding -# them to the application. -include(flutter/generated_plugins.cmake) - - -# === Installation === -# Support files are copied into place next to the executable, so that it can -# run in place. This is done instead of making a separate bundle (as on Linux) -# so that building and running from within Visual Studio will work. -set(BUILD_BUNDLE_DIR "$") -# Make the "install" step default, as it's required to run. -set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) -if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) -endif() - -set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") -set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") - -install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" - COMPONENT Runtime) - -install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" - COMPONENT Runtime) - -install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) - -if(PLUGIN_BUNDLED_LIBRARIES) - install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" - DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) -endif() - -# Fully re-copy the assets directory on each build to avoid having stale files -# from a previous install. -set(FLUTTER_ASSET_DIR_NAME "flutter_assets") -install(CODE " - file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") - " COMPONENT Runtime) -install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" - DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) - -# Install the AOT library on non-Debug builds only. -install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" - CONFIGURATIONS Profile;Release - COMPONENT Runtime) diff --git a/benchmarks/windows/flutter/CMakeLists.txt b/benchmarks/windows/flutter/CMakeLists.txt deleted file mode 100644 index 930d2071a..000000000 --- a/benchmarks/windows/flutter/CMakeLists.txt +++ /dev/null @@ -1,104 +0,0 @@ -# This file controls Flutter-level build steps. It should not be edited. -cmake_minimum_required(VERSION 3.14) - -set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") - -# Configuration provided via flutter tool. -include(${EPHEMERAL_DIR}/generated_config.cmake) - -# TODO: Move the rest of this into files in ephemeral. See -# https://github.com/flutter/flutter/issues/57146. -set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") - -# === Flutter Library === -set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") - -# Published to parent scope for install step. -set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) -set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) -set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) -set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) - -list(APPEND FLUTTER_LIBRARY_HEADERS - "flutter_export.h" - "flutter_windows.h" - "flutter_messenger.h" - "flutter_plugin_registrar.h" - "flutter_texture_registrar.h" -) -list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") -add_library(flutter INTERFACE) -target_include_directories(flutter INTERFACE - "${EPHEMERAL_DIR}" -) -target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") -add_dependencies(flutter flutter_assemble) - -# === Wrapper === -list(APPEND CPP_WRAPPER_SOURCES_CORE - "core_implementations.cc" - "standard_codec.cc" -) -list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") -list(APPEND CPP_WRAPPER_SOURCES_PLUGIN - "plugin_registrar.cc" -) -list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") -list(APPEND CPP_WRAPPER_SOURCES_APP - "flutter_engine.cc" - "flutter_view_controller.cc" -) -list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") - -# Wrapper sources needed for a plugin. -add_library(flutter_wrapper_plugin STATIC - ${CPP_WRAPPER_SOURCES_CORE} - ${CPP_WRAPPER_SOURCES_PLUGIN} -) -apply_standard_settings(flutter_wrapper_plugin) -set_target_properties(flutter_wrapper_plugin PROPERTIES - POSITION_INDEPENDENT_CODE ON) -set_target_properties(flutter_wrapper_plugin PROPERTIES - CXX_VISIBILITY_PRESET hidden) -target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) -target_include_directories(flutter_wrapper_plugin PUBLIC - "${WRAPPER_ROOT}/include" -) -add_dependencies(flutter_wrapper_plugin flutter_assemble) - -# Wrapper sources needed for the runner. -add_library(flutter_wrapper_app STATIC - ${CPP_WRAPPER_SOURCES_CORE} - ${CPP_WRAPPER_SOURCES_APP} -) -apply_standard_settings(flutter_wrapper_app) -target_link_libraries(flutter_wrapper_app PUBLIC flutter) -target_include_directories(flutter_wrapper_app PUBLIC - "${WRAPPER_ROOT}/include" -) -add_dependencies(flutter_wrapper_app flutter_assemble) - -# === Flutter tool backend === -# _phony_ is a non-existent file to force this command to run every time, -# since currently there's no way to get a full input/output list from the -# flutter tool. -set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") -set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) -add_custom_command( - OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} - ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} - ${CPP_WRAPPER_SOURCES_APP} - ${PHONY_OUTPUT} - COMMAND ${CMAKE_COMMAND} -E env - ${FLUTTER_TOOL_ENVIRONMENT} - "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" - windows-x64 $ - VERBATIM -) -add_custom_target(flutter_assemble DEPENDS - "${FLUTTER_LIBRARY}" - ${FLUTTER_LIBRARY_HEADERS} - ${CPP_WRAPPER_SOURCES_CORE} - ${CPP_WRAPPER_SOURCES_PLUGIN} - ${CPP_WRAPPER_SOURCES_APP} -) diff --git a/benchmarks/windows/flutter/generated_plugin_registrant.cc b/benchmarks/windows/flutter/generated_plugin_registrant.cc deleted file mode 100644 index 8b6d4680a..000000000 --- a/benchmarks/windows/flutter/generated_plugin_registrant.cc +++ /dev/null @@ -1,11 +0,0 @@ -// -// Generated file. Do not edit. -// - -// clang-format off - -#include "generated_plugin_registrant.h" - - -void RegisterPlugins(flutter::PluginRegistry* registry) { -} diff --git a/benchmarks/windows/flutter/generated_plugin_registrant.h b/benchmarks/windows/flutter/generated_plugin_registrant.h deleted file mode 100644 index dc139d85a..000000000 --- a/benchmarks/windows/flutter/generated_plugin_registrant.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// Generated file. Do not edit. -// - -// clang-format off - -#ifndef GENERATED_PLUGIN_REGISTRANT_ -#define GENERATED_PLUGIN_REGISTRANT_ - -#include - -// Registers Flutter plugins. -void RegisterPlugins(flutter::PluginRegistry* registry); - -#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/benchmarks/windows/flutter/generated_plugins.cmake b/benchmarks/windows/flutter/generated_plugins.cmake deleted file mode 100644 index b93c4c30c..000000000 --- a/benchmarks/windows/flutter/generated_plugins.cmake +++ /dev/null @@ -1,23 +0,0 @@ -# -# Generated file, do not edit. -# - -list(APPEND FLUTTER_PLUGIN_LIST -) - -list(APPEND FLUTTER_FFI_PLUGIN_LIST -) - -set(PLUGIN_BUNDLED_LIBRARIES) - -foreach(plugin ${FLUTTER_PLUGIN_LIST}) - add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) - target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) - list(APPEND PLUGIN_BUNDLED_LIBRARIES $) - list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) -endforeach(plugin) - -foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) - add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) - list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) -endforeach(ffi_plugin) diff --git a/benchmarks/windows/runner/CMakeLists.txt b/benchmarks/windows/runner/CMakeLists.txt deleted file mode 100644 index 17411a8ab..000000000 --- a/benchmarks/windows/runner/CMakeLists.txt +++ /dev/null @@ -1,39 +0,0 @@ -cmake_minimum_required(VERSION 3.14) -project(runner LANGUAGES CXX) - -# Define the application target. To change its name, change BINARY_NAME in the -# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer -# work. -# -# Any new source files that you add to the application should be added here. -add_executable(${BINARY_NAME} WIN32 - "flutter_window.cpp" - "main.cpp" - "utils.cpp" - "win32_window.cpp" - "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" - "Runner.rc" - "runner.exe.manifest" -) - -# Apply the standard set of build settings. This can be removed for applications -# that need different build settings. -apply_standard_settings(${BINARY_NAME}) - -# Add preprocessor definitions for the build version. -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") - -# Disable Windows macros that collide with C++ standard library functions. -target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") - -# Add dependency libraries and include directories. Add any application-specific -# dependencies here. -target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) -target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") - -# Run the Flutter tool portions of the build. This must not be removed. -add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/benchmarks/windows/runner/Runner.rc b/benchmarks/windows/runner/Runner.rc deleted file mode 100644 index 182b624d4..000000000 --- a/benchmarks/windows/runner/Runner.rc +++ /dev/null @@ -1,121 +0,0 @@ -// Microsoft Visual C++ generated resource script. -// -#pragma code_page(65001) -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -IDI_APP_ICON ICON "resources\\app_icon.ico" - - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) -#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD -#else -#define VERSION_AS_NUMBER 1,0,0,0 -#endif - -#if defined(FLUTTER_VERSION) -#define VERSION_AS_STRING FLUTTER_VERSION -#else -#define VERSION_AS_STRING "1.0.0" -#endif - -VS_VERSION_INFO VERSIONINFO - FILEVERSION VERSION_AS_NUMBER - PRODUCTVERSION VERSION_AS_NUMBER - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS__WINDOWS32 - FILETYPE VFT_APP - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904e4" - BEGIN - VALUE "CompanyName", "com.example" "\0" - VALUE "FileDescription", "benchmarks" "\0" - VALUE "FileVersion", VERSION_AS_STRING "\0" - VALUE "InternalName", "benchmarks" "\0" - VALUE "LegalCopyright", "Copyright (C) 2022 com.example. All rights reserved." "\0" - VALUE "OriginalFilename", "benchmarks.exe" "\0" - VALUE "ProductName", "benchmarks" "\0" - VALUE "ProductVersion", VERSION_AS_STRING "\0" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1252 - END -END - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED diff --git a/benchmarks/windows/runner/flutter_window.cpp b/benchmarks/windows/runner/flutter_window.cpp deleted file mode 100644 index b43b9095e..000000000 --- a/benchmarks/windows/runner/flutter_window.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "flutter_window.h" - -#include - -#include "flutter/generated_plugin_registrant.h" - -FlutterWindow::FlutterWindow(const flutter::DartProject& project) - : project_(project) {} - -FlutterWindow::~FlutterWindow() {} - -bool FlutterWindow::OnCreate() { - if (!Win32Window::OnCreate()) { - return false; - } - - RECT frame = GetClientArea(); - - // The size here must match the window dimensions to avoid unnecessary surface - // creation / destruction in the startup path. - flutter_controller_ = std::make_unique( - frame.right - frame.left, frame.bottom - frame.top, project_); - // Ensure that basic setup of the controller was successful. - if (!flutter_controller_->engine() || !flutter_controller_->view()) { - return false; - } - RegisterPlugins(flutter_controller_->engine()); - SetChildContent(flutter_controller_->view()->GetNativeWindow()); - return true; -} - -void FlutterWindow::OnDestroy() { - if (flutter_controller_) { - flutter_controller_ = nullptr; - } - - Win32Window::OnDestroy(); -} - -LRESULT -FlutterWindow::MessageHandler(HWND hwnd, UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept { - // Give Flutter, including plugins, an opportunity to handle window messages. - if (flutter_controller_) { - std::optional result = - flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, - lparam); - if (result) { - return *result; - } - } - - switch (message) { - case WM_FONTCHANGE: - flutter_controller_->engine()->ReloadSystemFonts(); - break; - } - - return Win32Window::MessageHandler(hwnd, message, wparam, lparam); -} diff --git a/benchmarks/windows/runner/flutter_window.h b/benchmarks/windows/runner/flutter_window.h deleted file mode 100644 index 6da0652f0..000000000 --- a/benchmarks/windows/runner/flutter_window.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef RUNNER_FLUTTER_WINDOW_H_ -#define RUNNER_FLUTTER_WINDOW_H_ - -#include -#include - -#include - -#include "win32_window.h" - -// A window that does nothing but host a Flutter view. -class FlutterWindow : public Win32Window { - public: - // Creates a new FlutterWindow hosting a Flutter view running |project|. - explicit FlutterWindow(const flutter::DartProject& project); - virtual ~FlutterWindow(); - - protected: - // Win32Window: - bool OnCreate() override; - void OnDestroy() override; - LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, - LPARAM const lparam) noexcept override; - - private: - // The project to run. - flutter::DartProject project_; - - // The Flutter instance hosted by this window. - std::unique_ptr flutter_controller_; -}; - -#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/benchmarks/windows/runner/main.cpp b/benchmarks/windows/runner/main.cpp deleted file mode 100644 index 644616c66..000000000 --- a/benchmarks/windows/runner/main.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include -#include -#include - -#include "flutter_window.h" -#include "utils.h" - -int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, - _In_ wchar_t *command_line, _In_ int show_command) { - // Attach to console when present (e.g., 'flutter run') or create a - // new console when running with a debugger. - if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { - CreateAndAttachConsole(); - } - - // Initialize COM, so that it is available for use in the library and/or - // plugins. - ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); - - flutter::DartProject project(L"data"); - - std::vector command_line_arguments = - GetCommandLineArguments(); - - project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); - - FlutterWindow window(project); - Win32Window::Point origin(10, 10); - Win32Window::Size size(1280, 720); - if (!window.CreateAndShow(L"benchmarks", origin, size)) { - return EXIT_FAILURE; - } - window.SetQuitOnClose(true); - - ::MSG msg; - while (::GetMessage(&msg, nullptr, 0, 0)) { - ::TranslateMessage(&msg); - ::DispatchMessage(&msg); - } - - ::CoUninitialize(); - return EXIT_SUCCESS; -} diff --git a/benchmarks/windows/runner/resource.h b/benchmarks/windows/runner/resource.h deleted file mode 100644 index 66a65d1e4..000000000 --- a/benchmarks/windows/runner/resource.h +++ /dev/null @@ -1,16 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by Runner.rc -// -#define IDI_APP_ICON 101 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 102 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif diff --git a/benchmarks/windows/runner/resources/app_icon.ico b/benchmarks/windows/runner/resources/app_icon.ico deleted file mode 100644 index c04e20caf..000000000 Binary files a/benchmarks/windows/runner/resources/app_icon.ico and /dev/null differ diff --git a/benchmarks/windows/runner/runner.exe.manifest b/benchmarks/windows/runner/runner.exe.manifest deleted file mode 100644 index a42ea7687..000000000 --- a/benchmarks/windows/runner/runner.exe.manifest +++ /dev/null @@ -1,20 +0,0 @@ - - - - - PerMonitorV2 - - - - - - - - - - - - - - - diff --git a/benchmarks/windows/runner/utils.cpp b/benchmarks/windows/runner/utils.cpp deleted file mode 100644 index f5bf9fa0f..000000000 --- a/benchmarks/windows/runner/utils.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include "utils.h" - -#include -#include -#include -#include - -#include - -void CreateAndAttachConsole() { - if (::AllocConsole()) { - FILE *unused; - if (freopen_s(&unused, "CONOUT$", "w", stdout)) { - _dup2(_fileno(stdout), 1); - } - if (freopen_s(&unused, "CONOUT$", "w", stderr)) { - _dup2(_fileno(stdout), 2); - } - std::ios::sync_with_stdio(); - FlutterDesktopResyncOutputStreams(); - } -} - -std::vector GetCommandLineArguments() { - // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. - int argc; - wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); - if (argv == nullptr) { - return std::vector(); - } - - std::vector command_line_arguments; - - // Skip the first argument as it's the binary name. - for (int i = 1; i < argc; i++) { - command_line_arguments.push_back(Utf8FromUtf16(argv[i])); - } - - ::LocalFree(argv); - - return command_line_arguments; -} - -std::string Utf8FromUtf16(const wchar_t* utf16_string) { - if (utf16_string == nullptr) { - return std::string(); - } - int target_length = ::WideCharToMultiByte( - CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, - -1, nullptr, 0, nullptr, nullptr); - std::string utf8_string; - if (target_length == 0 || target_length > utf8_string.max_size()) { - return utf8_string; - } - utf8_string.resize(target_length); - int converted_length = ::WideCharToMultiByte( - CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, - -1, utf8_string.data(), - target_length, nullptr, nullptr); - if (converted_length == 0) { - return std::string(); - } - return utf8_string; -} diff --git a/benchmarks/windows/runner/utils.h b/benchmarks/windows/runner/utils.h deleted file mode 100644 index 3879d5475..000000000 --- a/benchmarks/windows/runner/utils.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef RUNNER_UTILS_H_ -#define RUNNER_UTILS_H_ - -#include -#include - -// Creates a console for the process, and redirects stdout and stderr to -// it for both the runner and the Flutter library. -void CreateAndAttachConsole(); - -// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string -// encoded in UTF-8. Returns an empty std::string on failure. -std::string Utf8FromUtf16(const wchar_t* utf16_string); - -// Gets the command line arguments passed in as a std::vector, -// encoded in UTF-8. Returns an empty std::vector on failure. -std::vector GetCommandLineArguments(); - -#endif // RUNNER_UTILS_H_ diff --git a/benchmarks/windows/runner/win32_window.cpp b/benchmarks/windows/runner/win32_window.cpp deleted file mode 100644 index c10f08dc7..000000000 --- a/benchmarks/windows/runner/win32_window.cpp +++ /dev/null @@ -1,245 +0,0 @@ -#include "win32_window.h" - -#include - -#include "resource.h" - -namespace { - -constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; - -// The number of Win32Window objects that currently exist. -static int g_active_window_count = 0; - -using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); - -// Scale helper to convert logical scaler values to physical using passed in -// scale factor -int Scale(int source, double scale_factor) { - return static_cast(source * scale_factor); -} - -// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. -// This API is only needed for PerMonitor V1 awareness mode. -void EnableFullDpiSupportIfAvailable(HWND hwnd) { - HMODULE user32_module = LoadLibraryA("User32.dll"); - if (!user32_module) { - return; - } - auto enable_non_client_dpi_scaling = - reinterpret_cast( - GetProcAddress(user32_module, "EnableNonClientDpiScaling")); - if (enable_non_client_dpi_scaling != nullptr) { - enable_non_client_dpi_scaling(hwnd); - FreeLibrary(user32_module); - } -} - -} // namespace - -// Manages the Win32Window's window class registration. -class WindowClassRegistrar { - public: - ~WindowClassRegistrar() = default; - - // Returns the singleton registar instance. - static WindowClassRegistrar* GetInstance() { - if (!instance_) { - instance_ = new WindowClassRegistrar(); - } - return instance_; - } - - // Returns the name of the window class, registering the class if it hasn't - // previously been registered. - const wchar_t* GetWindowClass(); - - // Unregisters the window class. Should only be called if there are no - // instances of the window. - void UnregisterWindowClass(); - - private: - WindowClassRegistrar() = default; - - static WindowClassRegistrar* instance_; - - bool class_registered_ = false; -}; - -WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; - -const wchar_t* WindowClassRegistrar::GetWindowClass() { - if (!class_registered_) { - WNDCLASS window_class{}; - window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); - window_class.lpszClassName = kWindowClassName; - window_class.style = CS_HREDRAW | CS_VREDRAW; - window_class.cbClsExtra = 0; - window_class.cbWndExtra = 0; - window_class.hInstance = GetModuleHandle(nullptr); - window_class.hIcon = - LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); - window_class.hbrBackground = 0; - window_class.lpszMenuName = nullptr; - window_class.lpfnWndProc = Win32Window::WndProc; - RegisterClass(&window_class); - class_registered_ = true; - } - return kWindowClassName; -} - -void WindowClassRegistrar::UnregisterWindowClass() { - UnregisterClass(kWindowClassName, nullptr); - class_registered_ = false; -} - -Win32Window::Win32Window() { - ++g_active_window_count; -} - -Win32Window::~Win32Window() { - --g_active_window_count; - Destroy(); -} - -bool Win32Window::CreateAndShow(const std::wstring& title, - const Point& origin, - const Size& size) { - Destroy(); - - const wchar_t* window_class = - WindowClassRegistrar::GetInstance()->GetWindowClass(); - - const POINT target_point = {static_cast(origin.x), - static_cast(origin.y)}; - HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); - UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); - double scale_factor = dpi / 96.0; - - HWND window = CreateWindow( - window_class, title.c_str(), WS_OVERLAPPEDWINDOW | WS_VISIBLE, - Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), - Scale(size.width, scale_factor), Scale(size.height, scale_factor), - nullptr, nullptr, GetModuleHandle(nullptr), this); - - if (!window) { - return false; - } - - return OnCreate(); -} - -// static -LRESULT CALLBACK Win32Window::WndProc(HWND const window, - UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept { - if (message == WM_NCCREATE) { - auto window_struct = reinterpret_cast(lparam); - SetWindowLongPtr(window, GWLP_USERDATA, - reinterpret_cast(window_struct->lpCreateParams)); - - auto that = static_cast(window_struct->lpCreateParams); - EnableFullDpiSupportIfAvailable(window); - that->window_handle_ = window; - } else if (Win32Window* that = GetThisFromHandle(window)) { - return that->MessageHandler(window, message, wparam, lparam); - } - - return DefWindowProc(window, message, wparam, lparam); -} - -LRESULT -Win32Window::MessageHandler(HWND hwnd, - UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept { - switch (message) { - case WM_DESTROY: - window_handle_ = nullptr; - Destroy(); - if (quit_on_close_) { - PostQuitMessage(0); - } - return 0; - - case WM_DPICHANGED: { - auto newRectSize = reinterpret_cast(lparam); - LONG newWidth = newRectSize->right - newRectSize->left; - LONG newHeight = newRectSize->bottom - newRectSize->top; - - SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, - newHeight, SWP_NOZORDER | SWP_NOACTIVATE); - - return 0; - } - case WM_SIZE: { - RECT rect = GetClientArea(); - if (child_content_ != nullptr) { - // Size and position the child window. - MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, - rect.bottom - rect.top, TRUE); - } - return 0; - } - - case WM_ACTIVATE: - if (child_content_ != nullptr) { - SetFocus(child_content_); - } - return 0; - } - - return DefWindowProc(window_handle_, message, wparam, lparam); -} - -void Win32Window::Destroy() { - OnDestroy(); - - if (window_handle_) { - DestroyWindow(window_handle_); - window_handle_ = nullptr; - } - if (g_active_window_count == 0) { - WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); - } -} - -Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { - return reinterpret_cast( - GetWindowLongPtr(window, GWLP_USERDATA)); -} - -void Win32Window::SetChildContent(HWND content) { - child_content_ = content; - SetParent(content, window_handle_); - RECT frame = GetClientArea(); - - MoveWindow(content, frame.left, frame.top, frame.right - frame.left, - frame.bottom - frame.top, true); - - SetFocus(child_content_); -} - -RECT Win32Window::GetClientArea() { - RECT frame; - GetClientRect(window_handle_, &frame); - return frame; -} - -HWND Win32Window::GetHandle() { - return window_handle_; -} - -void Win32Window::SetQuitOnClose(bool quit_on_close) { - quit_on_close_ = quit_on_close; -} - -bool Win32Window::OnCreate() { - // No-op; provided for subclasses. - return true; -} - -void Win32Window::OnDestroy() { - // No-op; provided for subclasses. -} diff --git a/benchmarks/windows/runner/win32_window.h b/benchmarks/windows/runner/win32_window.h deleted file mode 100644 index 17ba43112..000000000 --- a/benchmarks/windows/runner/win32_window.h +++ /dev/null @@ -1,98 +0,0 @@ -#ifndef RUNNER_WIN32_WINDOW_H_ -#define RUNNER_WIN32_WINDOW_H_ - -#include - -#include -#include -#include - -// A class abstraction for a high DPI-aware Win32 Window. Intended to be -// inherited from by classes that wish to specialize with custom -// rendering and input handling -class Win32Window { - public: - struct Point { - unsigned int x; - unsigned int y; - Point(unsigned int x, unsigned int y) : x(x), y(y) {} - }; - - struct Size { - unsigned int width; - unsigned int height; - Size(unsigned int width, unsigned int height) - : width(width), height(height) {} - }; - - Win32Window(); - virtual ~Win32Window(); - - // Creates and shows a win32 window with |title| and position and size using - // |origin| and |size|. New windows are created on the default monitor. Window - // sizes are specified to the OS in physical pixels, hence to ensure a - // consistent size to will treat the width height passed in to this function - // as logical pixels and scale to appropriate for the default monitor. Returns - // true if the window was created successfully. - bool CreateAndShow(const std::wstring& title, - const Point& origin, - const Size& size); - - // Release OS resources associated with window. - void Destroy(); - - // Inserts |content| into the window tree. - void SetChildContent(HWND content); - - // Returns the backing Window handle to enable clients to set icon and other - // window properties. Returns nullptr if the window has been destroyed. - HWND GetHandle(); - - // If true, closing this window will quit the application. - void SetQuitOnClose(bool quit_on_close); - - // Return a RECT representing the bounds of the current client area. - RECT GetClientArea(); - - protected: - // Processes and route salient window messages for mouse handling, - // size change and DPI. Delegates handling of these to member overloads that - // inheriting classes can handle. - virtual LRESULT MessageHandler(HWND window, - UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept; - - // Called when CreateAndShow is called, allowing subclass window-related - // setup. Subclasses should return false if setup fails. - virtual bool OnCreate(); - - // Called when Destroy is called. - virtual void OnDestroy(); - - private: - friend class WindowClassRegistrar; - - // OS callback called by message pump. Handles the WM_NCCREATE message which - // is passed when the non-client area is being created and enables automatic - // non-client DPI scaling so that the non-client area automatically - // responsponds to changes in DPI. All other messages are handled by - // MessageHandler. - static LRESULT CALLBACK WndProc(HWND const window, - UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept; - - // Retrieves a class instance pointer for |window| - static Win32Window* GetThisFromHandle(HWND const window) noexcept; - - bool quit_on_close_ = false; - - // window handle for top level window. - HWND window_handle_ = nullptr; - - // window handle for hosted content. - HWND child_content_ = nullptr; -}; - -#endif // RUNNER_WIN32_WINDOW_H_ diff --git a/context.md b/context.md new file mode 100644 index 000000000..453480a3a --- /dev/null +++ b/context.md @@ -0,0 +1,1543 @@ + +Beginning of file: lib/mix.dart + + +Beginning of file: lib/exports.dart + + +Beginning of file: lib/src/core/directives/directives/glitch.dart + +class GlitchText extends StatefulWidget +- String text +- TextStyle style +- _GlitchTextState createState() +class _GlitchTextState extends State +- Unknown _random +- Timer _positionTimer +- Timer _shadowTimer +- double _offsetX +- double _offsetY +- double _shadowOffsetX +- double _shadowOffsetY +- double _scale +- void initState() +- void _randomizePosition(Timer timer) +- void _randomizeShadow(Timer timer) +- void dispose() +- Widget build(BuildContext context) + +Beginning of file: lib/src/core/directives/directives/counter.dart + +class MyApp extends StatelessWidget +- Widget build(BuildContext context) +class NumberTickerExample extends StatefulWidget +- _NumberTickerExampleState createState() +class _NumberTickerExampleState extends State +- Unknown _textController +- double _value +- void _updateValue() +- Widget build(BuildContext context) +class AnimatedNumberTicker extends StatefulWidget +- double value +- _AnimatedNumberTickerState createState() +class _AnimatedNumberTickerState extends State with SingleTickerProviderStateMixin +- AnimationController _controller +- Animation _animation +- void initState() +- void didUpdateWidget(AnimatedNumberTicker oldWidget) +- void dispose() +- Widget build(BuildContext context) + +Beginning of file: lib/src/core/directives/directives/controllers.dart + +class Character +- String from +- String to +- int start +- int end +- String char +class TextDecodingController +- Function(String value) _fn +- String _data +- int _frame +- Unknown _chars +- Unknown _queue +- Unknown _random +- Ticker? _ticker +- void setData(String newText) +- void dispose() +- void _startTicker() +- void _update(Duration elapsedTime) +- String _randomChar() + +Beginning of file: lib/src/core/directives/color_dto_directives.dart + + +Beginning of file: lib/src/core/directives/text_directive.dart + +class UppercaseDirective extends TextDirective +- String modify(String value) +class CapitalizeDirective extends TextDirective +- String modify(String value) +class LowercaseDirective extends TextDirective +- String modify(String value) +class SentenceCaseDirective extends TextDirective +- String modify(String value) +class TitleCaseDirective extends TextDirective +- String modify(String value) +class TextDirective extends Directive +- String modify(String value) + +Beginning of file: lib/src/core/directives/directive_attribute.dart + +class Directive with Comparable +- T modify(T value) +- get null props + +Beginning of file: lib/src/core/dto/radius_dto.dart + +class RadiusDto extends Dto +- Unknown zero +- double? _x +- double? _y +- RadiusDto? maybeFrom(Radius? radius) +- get double? x +- get double? y +- RadiusDto merge(RadiusDto? other) +- Radius resolve(MixData mix) +- get null props + +Beginning of file: lib/src/core/dto/color_dto.dart + +class ColorDto extends ModifiableDto +- ColorDto? maybeFrom(Color? color) +- ColorDto merge(ColorDto? other) +- Color resolve(MixData mix) +- get null props + +Beginning of file: lib/src/core/dto/double_dto.dart + +class DoubleAttribute extends StyleAttribute +- DoubleDto value +- DoubleAttribute merge(DoubleAttribute? other) +- double resolve(MixData mix) +- get List props +class DoubleDto extends ModifiableDto +- DoubleDto? maybeFrom(double? value) +- DoubleDto merge(DoubleDto? other) +- double resolve(MixData mix) +- get List props + +Beginning of file: lib/src/core/dto/border_side_dto.dart + +class BorderSideDto extends Dto +- ColorDto? color +- double? width +- BorderStyle? style +- double? strokeAlign +- Unknown _default +- BorderSideDto merge(BorderSideDto? other) +- BorderSide resolve(MixData mix) +- get null props + +Beginning of file: lib/src/core/variants/variant.dart + +class Variant +- String name +- VariantOperation &(Variant variant) +- VariantOperation |(Variant variant) +- VariantAttribute call() +- bool ==(Object other) +- String toString() +- get int hashCode + +Beginning of file: lib/src/core/variants/context_variant.dart + +class ContextVariant extends Variant +- ShouldApplyFunction _shouldApply +- get null props +- bool shouldApply(BuildContext context) +- ContextVariantAttribute call() + +Beginning of file: lib/src/core/variants/variant_operation.dart + +class VariantOperation +- List variants +- EnumVariantOperator operator +- VariantOperation &(Variant variant) +- VariantOperation |(Variant variant) +- NestedStyleAttribute call() +- List _buildOrOperations(List attributes) +- List _buildAndOperations(List attributes) +- bool ==(Object other) +- String toString() +- get int hashCode + +Beginning of file: lib/src/core/decorators/decorator.dart + +class Decorator extends StyleAttribute +- Decorator merge(Decorator? other) +- Widget build(Widget child, MixData mix) + +Beginning of file: lib/src/core/decorators/widget_decorator_wrapper.dart + +class WidgetDecoratorWrapper extends StatelessWidget +- MixData mix +- Widget child +- Widget build(BuildContext context) + +Beginning of file: lib/src/core/decorators/built_in_decorators/clip_decorator.dart + +class ClipDecorator extends Decorator +- BorderRadiusAttribute? borderRadius +- ClipDecoratorType clipType +- ClipDecorator merge(ClipDecorator other) +- ClipDecoratorSpec resolve(MixData mix) +- get null props +- Widget build(Widget child, MixData mix) +class ClipDecoratorSpec extends Spec +- BorderRadiusGeometry borderRadius +- ClipDecoratorType clipType +- ClipDecoratorSpec lerp(ClipDecoratorSpec other, double t) +- ClipDecoratorSpec copyWith() +- get null props +class AnimatedClipRRect extends StatelessWidget +- Widget _builder(BuildContext context, BorderRadius radius, Widget? child) +- Duration duration +- Curve curve +- BorderRadius borderRadius +- Widget child +- Widget build(BuildContext context) +class TriangleClipper extends CustomClipper +- Path getClip(Size size) +- bool shouldReclip(TriangleClipper oldClipper) + +Beginning of file: lib/src/core/decorators/built_in_decorators/rotate.dart + +class RotateDecorator extends Decorator +- int quarterTurns +- RotateDecorator merge(RotateDecorator other) +- int resolve(MixData mix) +- get null props +- Widget build(Widget child, MixData mix) +class RotateSpec +- int quarterTurns + +Beginning of file: lib/src/core/decorators/built_in_decorators/flexible.dart + +class FlexibleDecorator extends Decorator +- int? _flex +- FlexFit? _flexFit +- FlexibleDecorator merge(FlexibleDecorator other) +- FlexibleDecoratorSpec resolve(MixData mix) +- get null props +- Widget build() +class FlexibleDecoratorSpec +- int flex +- FlexFit flexFit + +Beginning of file: lib/src/core/decorators/built_in_decorators/aspect_ratio.dart + +class AspectRatioDecorator extends Decorator +- DoubleDto _aspectRatio +- AspectRatioDecorator merge(AspectRatioDecorator other) +- double resolve(MixData mix) +- get null props +- Widget build(Widget child, MixData mix) + +Beginning of file: lib/src/core/decorators/built_in_decorators/opacity.dart + +class OpacityDecorator extends Decorator +- DoubleDto value +- OpacityDecorator merge(OpacityDecorator? other) +- double resolve(MixData mix) +- get null props +- Widget build() + +Beginning of file: lib/src/core/decorators/built_in_decorators/scale.dart + +class ScaleDecorator extends Decorator +- DoubleDto _scale +- ScaleDecorator merge(ScaleDecorator? other) +- double resolve(MixData mix) +- get null props +- Widget build(Widget child, MixData mix) + +Beginning of file: lib/src/core/attribute.dart + +class Dto with Comparable, Mergeable, Resolvable +class Attribute with Comparable, Mergeable +- get Object type +- T resolve(MixData mix) +- T merge(T? other) +- M mergeAttr(M? current, M? other) + +Beginning of file: lib/src/deprecations.dart + +- get SpreadPositionalParams mix +- StyleMix withVariants(List variants) +- StyleMix addAttributes(List attributes) +- StyleMix withManyVariants(List variants) +- get SpreadPositionalParams apply +- StyleMix withVariant(Variant variant) +- StyleMix combineAll(List mixes) +- StyleMix withMaybeVariant(Variant? variant) +- StyleMix maybeApply(StyleMix? mix) +- StyleMix applyMaybe(StyleMix? mix) + +Beginning of file: lib/src/utils/padding.util.dart + + +Beginning of file: lib/src/utils/container_util.dart + + +Beginning of file: lib/src/utils/height.util.dart + + +Beginning of file: lib/src/utils/gradient_util.dart + + +Beginning of file: lib/src/utils/border_util.dart + + +Beginning of file: lib/src/utils/margin_util.dart + + +Beginning of file: lib/src/utils/alignment_util.dart + + +Beginning of file: lib/src/utils/image_util.dart + + +Beginning of file: lib/src/utils/width_util.dart + + +Beginning of file: lib/src/utils/text_util.dart + + +Beginning of file: lib/src/utils/transform_util.dart + + +Beginning of file: lib/src/utils/pressable_util.dart + + +Beginning of file: lib/src/utils/box_constraints_util.dart + + +Beginning of file: lib/src/utils/visible_util.dart + + +Beginning of file: lib/src/utils/stack_fit_util.dart + + +Beginning of file: lib/src/utils/text_style_util.dart + + +Beginning of file: lib/src/utils/flex_util.dart + + +Beginning of file: lib/src/utils/padding_util.dart + + +Beginning of file: lib/src/utils/text_directives_util.dart + + +Beginning of file: lib/src/utils/image.util.dart + + +Beginning of file: lib/src/utils/text_direction_util.dart + + +Beginning of file: lib/src/utils/height_util.dart + + +Beginning of file: lib/src/utils/stack_util.dart + + +Beginning of file: lib/src/utils/helper_util.dart + +class HelperUtility +- NestedStyleAttribute apply(List mixes) +class SpreadNamedParams +- FunctionWithMapParam _function +- Map _initialParams +class SpreadPositionalParams +- FunctionWithListParam fn +- ReturnType call() + +Beginning of file: lib/src/utils/context_variant_util.dart + + +Beginning of file: lib/src/utils/border_radius_util.dart + + +Beginning of file: lib/src/utils/icon_util.dart + + +Beginning of file: lib/src/utils/vertical_direction_util.dart + + +Beginning of file: lib/src/attributes/variant_attribute.dart + +class VariantAttribute extends Attribute +- T variant +- StyleMix _style +- get MixValues value +- VariantAttribute merge(VariantAttribute other) +- String toString() +- get Key mergeKey +- get null props +class ContextVariantAttribute extends VariantAttribute +- bool shouldApply(BuildContext context) +- ContextVariantAttribute merge(ContextVariantAttribute other) + +Beginning of file: lib/src/attributes/flex_fit_attribute.dart + +class FlexFitAttribute extends StyleAttribute +- FlexFit fit +- FlexFitAttribute merge(FlexFitAttribute? other) +- FlexFit resolve(MixData mix) +- get List props + +Beginning of file: lib/src/attributes/image_attribute.dart + +class ImageAttributes extends SpecAttribute +- ImageProviderAttribute? image +- WidthAttribute? width +- HeightAttribute? height +- ColorDto? color +- ImageRepeatAttribute? repeat +- BoxFitAttribute? fit +- ImageAttributes merge(ImageAttributes? other) +- ImageSpec resolve(MixData mix) +- get null props +class ImageSpec extends Spec +- ImageProvider? image +- double? width +- Color? color +- ImageRepeat? repeat +- BoxFit? fit +- ImageSpec lerp(ImageSpec? other, double t) +- ImageSpec copyWith() +- get null props + +Beginning of file: lib/src/attributes/text_style_attribute.dart + +class TextStyleAttribute extends StyleAttribute +- String? fontFamily +- FontWeight? fontWeight +- bool? inherit +- FontStyle? fontStyle +- double? fontSize +- double? letterSpacing +- double? wordSpacing +- TextBaseline? textBaseline +- ColorDto? color +- ColorDto? backgroundColor +- List? shadows +- List? fontFeatures +- TextDecoration? decoration +- ColorDto? decorationColor +- TextDecorationStyle? decorationStyle +- Locale? locale +- String? debugLabel +- double? height +- Paint? foreground +- Paint? background +- double? decorationThickness +- List? fontFamilyFallback +- TextStyleToken? styleToken +- TextStyleAttribute merge(TextStyleAttribute? other) +- TextStyle resolve(MixData mix) +- get null props + +Beginning of file: lib/src/attributes/text_direction_attribute.dart + +class TextDirectionAttribute extends StyleAttribute +- TextDirection direction +- TextDirectionAttribute? maybeFrom(TextDirection? direction) +- get TextDirection value +- TextDirectionAttribute merge(TextDirectionAttribute? other) +- TextDirection resolve(MixData mix) +- get List props + +Beginning of file: lib/src/attributes/common_attribute.dart + +class CommonAttributes extends StyleAttribute +- DurationAttribute? _animationDuration +- CurveAttribute? _animationCurve +- TextDirectionAttribute? _textDirection +- VisibleAttribute? _visible +- CommonAttributes merge(CommonAttributes? other) +- CommonSpec resolve(MixData mix) +- get null props +class CommonSpec extends Spec +- bool visible +- TextDirection textDirection +- Duration animationDuration +- Curve animationCurve +- Unknown defaults +- CommonSpec copyWith() +- CommonSpec lerp(CommonSpec other, double t) +- get null props + +Beginning of file: lib/src/attributes/vertical_direction_attribute.dart + +class VerticalDirectionAttribute extends StyleAttribute +- VerticalDirection direction +- VerticalDirectionAttribute merge(VerticalDirectionAttribute? other) +- VerticalDirection resolve(MixData mix) +- get List props + +Beginning of file: lib/src/attributes/text_attribute.dart + +class TextAttributes extends StyleAttribute +- List _directives +- TextHeightBehavior? _textHeightBehavior +- int? _maxLines +- TextWidthBasis? _textWidthBasis +- double? _textScaleFactor +- TextOverflowAttribute? _overflow +- TextAlignAttribute? _textAlign +- bool? _softWrap +- Locale? _locale +- StrutStyleAttribute? _strutStyle +- List? _styles +- TextDirectionAttribute? _textDirection +- TextAttributes merge(TextAttributes? other) +- TextSpec resolve(MixData mix) +- get null props +class TextSpec extends Spec +- bool softWrap +- TextOverflow overflow +- StrutStyle? strutStyle +- TextAlign? textAlign +- Locale? locale +- double? textScaleFactor +- int? maxLines +- TextWidthBasis? textWidthBasis +- TextHeightBehavior? textHeightBehavior +- TextStyle? style +- TextDirection? textDirection +- List directives +- String applyTextDirectives(String? text) +- TextSpec lerp(TextSpec other, double t) +- TextSpec copyWith() +- get List props + +Beginning of file: lib/src/attributes/strut_style_attribute.dart + +class StrutStyleAttribute extends StyleAttribute +- String? fontFamily +- List? fontFamilyFallback +- double? fontSize +- FontWeight? fontWeight +- FontStyle? fontStyle +- double? height +- double? leading +- bool? forceStrutHeight +- Unknown _default +- StrutStyleAttribute? maybeFrom(StrutStyle? strutStyle) +- StrutStyleAttribute merge(StrutStyleAttribute? other) +- StrutStyle resolve(MixData mix) +- get null props + +Beginning of file: lib/src/attributes/gradient_attribute.dart + +class GradientAttribute extends StyleAttribute +- Gradient _gradient +- get Gradient value +- GradientAttribute merge(GradientAttribute? other) +- Gradient resolve(MixData mix) +- get null props + +Beginning of file: lib/src/attributes/main_axis_alignment_attribute.dart + +class MainAxisAlignmentAttribute extends StyleAttribute +- MainAxisAlignment alignment +- MainAxisAlignmentAttribute merge(MainAxisAlignmentAttribute? other) +- MainAxisAlignment resolve(MixData mix) +- get List props + +Beginning of file: lib/src/attributes/visible_attribute.dart + +class VisibleAttribute extends StyleAttribute +- bool _visible +- VisibleAttribute merge(VisibleAttribute? other) +- bool resolve(MixData mix) +- get null props + +Beginning of file: lib/src/attributes/box_fit_attribute.dart + +class BoxFitAttribute extends StyleAttribute +- BoxFit fit +- BoxFitAttribute merge(BoxFitAttribute? other) +- BoxFit resolve(MixData mix) +- get List props + +Beginning of file: lib/src/attributes/cross_axis_alignment_attribute.dart + +class CrossAxisAlignmentAttribute extends StyleAttribute +- CrossAxisAlignment alignment +- CrossAxisAlignmentAttribute merge(CrossAxisAlignmentAttribute? other) +- CrossAxisAlignment resolve(MixData mix) +- get List props + +Beginning of file: lib/src/attributes/matrix4_attribute.dart + +class Matrix4Attribute extends StyleAttribute +- Matrix4 matrix +- Matrix4 resolve(MixData mix) +- Matrix4Attribute merge(Matrix4Attribute? other) +- get null props + +Beginning of file: lib/src/attributes/image_provider_attribute.dart + +class ImageProviderAttribute extends StyleAttribute +- ImageProviderAttribute merge(ImageProviderAttribute? other) +- T resolve(MixData mix) +class NetworkImageAttribute extends ImageProviderAttribute +- String imageUrl +- NetworkImageAttribute merge(NetworkImageAttribute? other) +- NetworkImage resolve(MixData mix) +- get List props +class AssetImageAttribute extends ImageProviderAttribute +- String assetName +- AssetImageAttribute merge(AssetImageAttribute? other) +- AssetImage resolve(MixData mix) +- get List props +class FileImageAttribute extends ImageProviderAttribute +- File file +- FileImageAttribute merge(FileImageAttribute? other) +- FileImage resolve(MixData mix) +- get List props +class MemoryImageAttribute extends ImageProviderAttribute +- Uint8List bytes +- MemoryImageAttribute merge(MemoryImageAttribute? other) +- MemoryImage resolve(MixData mix) +- get List props +class ExactAssetImageAttribute extends ImageProviderAttribute +- String assetName +- double scale +- ExactAssetImageAttribute merge(ExactAssetImageAttribute? other) +- ExactAssetImage resolve(MixData mix) +- get List props + +Beginning of file: lib/src/attributes/flex_attribute.dart + +class FlexAttributes extends SpecAttribute +- AxisAttribute? direction +- MainAxisAlignmentAttribute? mainAxisAlignment +- CrossAxisAlignmentAttribute? crossAxisAlignment +- MainAxisSizeAttribute? mainAxisSize +- VerticalDirectionAttribute? verticalDirection +- TextDirectionAttribute? textDirection +- TextBaselineAttribute? textBaseline +- ClipAttribute? clipBehavior +- FlexAttributes merge(FlexAttributes? other) +- FlexSpec resolve(MixData mix) +- get List props +class FlexSpec extends Spec +- Axis? direction +- MainAxisAlignment? mainAxisAlignment +- CrossAxisAlignment? crossAxisAlignment +- MainAxisSize? mainAxisSize +- VerticalDirection? verticalDirection +- TextDirection? textDirection +- TextBaseline? textBaseline +- Clip? clipBehavior +- FlexSpec lerp(FlexSpec other, double t) +- FlexSpec copyWith() +- get List props + +Beginning of file: lib/src/attributes/style_attribute.dart + +class StyleAttribute extends Attribute with Resolvable +- K? resolveAttr(R? resolvable, MixData mix) +- K? resolveDto(R? resolvable, MixData mix) +- List combinedAttrList(List? current, List? other) +- List mergeAttrList(List? current, List? other) +- M mergeAttr(M? current, M? other) +class ModifiableDto extends Dto +- T value +- ValueModifier? modifier +- T modify(T valueToModify) +class SpecAttribute extends StyleAttribute +class Spec extends ThemeExtension with Comparable +- Duration lerpDuration(Duration a, Duration b, double t) +- int lerpInt(int a, int b, double t) +- N? genericNumLerp(N? a, N? b, double t) +- P snap(P from, P to, double t) +- List resolveAll(MixData mix) + +Beginning of file: lib/src/attributes/box_border_attribute.dart + +class BoxBorderAttribute extends StyleAttribute +- BorderSideDto? _top +- BorderSideDto? _right +- BorderSideDto? _bottom +- BorderSideDto? _left +- BorderSideDto? _start +- BorderSideDto? _end +- get BorderSideDto? top +- get BorderSideDto? right +- get BorderSideDto? bottom +- get BorderSideDto? left +- get BorderSideDto? start +- get BorderSideDto? end +- get bool _isDirectional +- BoxBorderAttribute merge(BoxBorderAttribute? other) +- BoxBorder resolve(MixData mix) +- get null props + +Beginning of file: lib/src/attributes/duration_attribute.dart + +class DurationAttribute extends StyleAttribute +- Duration duration +- DurationAttribute merge(DurationAttribute? other) +- Duration resolve(MixData mix) +- get List props + +Beginning of file: lib/src/attributes/shadow_attribute.dart + +class ShadowAttribute extends StyleAttribute +- ColorDto? color +- Offset? offset +- double? blurRadius +- T resolve(MixData mix) +- ShadowAttribute merge(ShadowAttribute? other) +- get null props + +Beginning of file: lib/src/attributes/curve_attribute.dart + +class CurveAttribute extends StyleAttribute +- Curve curve +- CurveAttribute merge(CurveAttribute? other) +- Curve resolve(MixData mix) +- get List props + +Beginning of file: lib/src/attributes/alignment_geometry_attribute.dart + +class AlignmentGeometryAttribute extends StyleAttribute +- AlignmentGeometryAttribute? maybeFrom(AlignmentGeometry? alignment) +- AlignmentGeometryAttribute from(AlignmentGeometry alignment) +- AlignmentGeometryAttribute merge(AlignmentGeometryAttribute? other) +- T resolve(MixData mix) +class AlignmentAttribute extends AlignmentGeometryAttribute +- double? x +- double? y +- AlignmentAttribute merge(AlignmentAttribute? other) +- Alignment resolve(MixData mix) +- get null props +class AlignmentDirectionalAttribute extends AlignmentGeometryAttribute +- double? start +- double? y +- AlignmentDirectionalAttribute merge(AlignmentDirectionalAttribute? other) +- AlignmentDirectional resolve(MixData mix) +- get null props + +Beginning of file: lib/src/attributes/box_shadow_attribute.dart + +class BoxShadowAttribute extends ShadowAttribute +- double? spreadRadius +- BoxShadow resolve(MixData mix) +- BoxShadowAttribute merge(BoxShadowAttribute? other) +- get null props + +Beginning of file: lib/src/attributes/clip_attribute.dart + +class ClipAttribute extends StyleAttribute +- Clip clip +- ClipAttribute merge(ClipAttribute? other) +- Clip resolve(MixData mix) +- get List props + +Beginning of file: lib/src/attributes/border_radius_geometry_attribute.dart + +class BorderRadiusGeometryAttribute extends StyleAttribute +- BorderRadiusGeometryAttribute from(BorderRadiusGeometry borderRadius) +- BorderRadiusGeometryAttribute merge(BorderRadiusGeometryAttribute? other) +- T resolve(MixData mix) +class BorderRadiusAttribute extends BorderRadiusGeometryAttribute +- RadiusDto? topLeft +- RadiusDto? topRight +- RadiusDto? bottomLeft +- RadiusDto? bottomRight +- BorderRadiusAttribute merge(BorderRadiusAttribute? other) +- BorderRadius resolve(MixData mix) +- get null props +class BorderRadiusDirectionalAttribute extends BorderRadiusGeometryAttribute +- Unknown zero +- RadiusDto? topStart +- RadiusDto? topEnd +- RadiusDto? bottomStart +- RadiusDto? bottomEnd +- BorderRadiusDirectionalAttribute merge(BorderRadiusDirectionalAttribute? other) +- BorderRadiusDirectional resolve(MixData mix) +- get null props + +Beginning of file: lib/src/attributes/text_overflow_attribute.dart + +class TextOverflowAttribute extends StyleAttribute +- TextOverflow overflow +- TextOverflowAttribute? maybeFrom(TextOverflow? overflow) +- TextOverflowAttribute merge(TextOverflowAttribute? other) +- TextOverflow resolve(MixData mix) +- get List props + +Beginning of file: lib/src/attributes/axis_attribute.dart + +class AxisAttribute extends StyleAttribute +- Axis axis +- AxisAttribute merge(AxisAttribute? other) +- Axis resolve(MixData mix) +- get List props + +Beginning of file: lib/src/attributes/image_repeat_attribute.dart + +class ImageRepeatAttribute extends StyleAttribute +- ImageRepeat imageRepeat +- ImageRepeatAttribute merge(ImageRepeatAttribute? other) +- ImageRepeat resolve(MixData mix) +- get List props + +Beginning of file: lib/src/attributes/box_constraints_attribute.dart + +class BoxConstraintsAttribute extends StyleAttribute +- double? minWidth +- double? maxWidth +- double? minHeight +- double? maxHeight +- BoxConstraintsAttribute merge(BoxConstraintsAttribute? other) +- BoxConstraints resolve(MixData mix) +- get null props + +Beginning of file: lib/src/attributes/stack_fit_attribute.dart + +class StackFitAttribute extends StyleAttribute +- StackFit fit +- StackFitAttribute merge(StackFitAttribute? other) +- StackFit resolve(MixData mix) +- get List props + +Beginning of file: lib/src/attributes/container_attribute.dart + +class ContainerAttributes extends SpecAttribute +- AlignmentGeometryAttribute? alignment +- PaddingAttribute? padding +- MarginAttribute? margin +- BoxConstraintsAttribute? constraints +- DecorationAttribute? decoration +- WidthAttribute? width +- HeightAttribute? height +- Matrix4Attribute? transform +- BackgroundColorAttribute? color +- ClipAttribute? clipBehavior +- ContainerAttributes merge(ContainerAttributes? other) +- ContainerSpec resolve(MixData mix) +- get List props +class ContainerSpec extends Spec +- AlignmentGeometry? alignment +- EdgeInsetsGeometry? padding +- EdgeInsetsGeometry? margin +- BoxConstraints? constraints +- Decoration? decoration +- double? width +- double? height +- Matrix4? transform +- Color? color +- Clip? clipBehavior +- ContainerSpec copyWith() +- ContainerSpec lerp(ContainerSpec other, double t) +- get null props + +Beginning of file: lib/src/attributes/nested_attribute.dart + +class NestedStyleAttribute extends Attribute +- StyleMix style +- NestedStyleAttribute merge(NestedStyleAttribute? other) +- get null props + +Beginning of file: lib/src/attributes/size_attribute.dart + +class HeightAttribute extends DoubleAttribute +- HeightAttribute merge(HeightAttribute? other) +class WidthAttribute extends DoubleAttribute +- WidthAttribute merge(WidthAttribute? other) + +Beginning of file: lib/src/attributes/text_align_attribute.dart + +class TextAlignAttribute extends StyleAttribute +- TextAlign align +- TextAlignAttribute? maybeFrom(TextAlign? align) +- TextAlignAttribute merge(TextAlignAttribute? other) +- TextAlign resolve(MixData mix) +- get List props + +Beginning of file: lib/src/attributes/color_attribute.dart + +class ColorAttribute extends StyleAttribute +- ColorDto color +- ColorAttribute merge(ColorAttribute? other) +- Color resolve(MixData mix) +- get null props +class BackgroundColorAttribute extends ColorAttribute +- BackgroundColorAttribute merge(BackgroundColorAttribute? other) + +Beginning of file: lib/src/attributes/decoration_attribute.dart + +class DecorationAttribute extends StyleAttribute +- DecorationAttribute from(Decoration decoration) +- DecorationAttribute merge(DecorationAttribute? other) +class BoxDecorationAttribute extends DecorationAttribute +- ColorDto? color +- BoxBorderAttribute? border +- BorderRadiusGeometryAttribute? borderRadius +- GradientAttribute? gradient +- List? boxShadow +- BoxShape? shape +- BoxDecorationAttribute merge(BoxDecorationAttribute? other) +- BoxDecoration resolve(MixData mix) +- get null props +class ShapeDecorationAttribute extends DecorationAttribute +- ColorDto? color +- ShapeBorder? shape +- GradientAttribute? gradient +- List? boxShadow +- ShapeDecorationAttribute merge(ShapeDecorationAttribute? other) +- ShapeDecoration resolve(MixData mix) +- get List props + +Beginning of file: lib/src/attributes/space_attribute.dart + +class PaddingAttribute extends StyleAttribute +- double? _top +- double? _bottom +- double? _left +- double? _right +- double? _start +- double? _end +- get double? top +- get double? bottom +- get double? left +- get double? right +- get double? start +- get double? end +- get bool _isDirectional +- PaddingAttribute merge(PaddingAttribute? other) +- EdgeInsetsGeometry resolve(MixData mix) +- get null props +class MarginAttribute extends StyleAttribute +- double? _top +- double? _bottom +- double? _left +- double? _right +- double? _start +- double? _end +- get double? top +- get double? bottom +- get double? left +- get double? right +- get double? start +- get double? end +- get bool _isDirectional +- MarginAttribute merge(MarginAttribute? other) +- EdgeInsetsGeometry resolve(MixData mix) +- get null props + +Beginning of file: lib/src/attributes/text_baseline_attribute.dart + +class TextBaselineAttribute extends StyleAttribute +- TextBaseline baseline +- TextBaselineAttribute merge(TextBaselineAttribute? other) +- TextBaseline resolve(MixData mix) +- get List props + +Beginning of file: lib/src/attributes/stack_attribute.dart + +class StackAttributes extends SpecAttribute +- AlignmentGeometryAttribute? alignment +- StackFitAttribute? fit +- TextDirectionAttribute? textDirection +- ClipAttribute? clipBehavior +- StackAttributes merge(StackAttributes? other) +- StackSpec resolve(MixData mix) +- get List props +class StackSpec extends Spec +- AlignmentGeometry? alignment +- StackFit? fit +- TextDirection? textDirection +- Clip? clipBehavior +- StackSpec lerp(StackSpec other, double t) +- StackSpec copyWith() +- get List props + +Beginning of file: lib/src/attributes/main_axis_size_attribute.dart + +class MainAxisSizeAttribute extends StyleAttribute +- MainAxisSize size +- MainAxisSizeAttribute merge(MainAxisSizeAttribute? other) +- MainAxisSize resolve(MixData mix) +- get List props + +Beginning of file: lib/src/attributes/icon_attribute.dart + +class IconAttributes extends StyleAttribute +- ColorDto? color +- DoubleDto? size +- IconData? icon +- IconAttributes merge(IconAttributes? other) +- IconSpec resolve(MixData mix) +- get List props +class IconSpec extends Spec +- Color? color +- double? size +- IconData? icon +- IconSpec lerp(IconSpec other, double t) +- IconSpec copyWith() +- get null props + +Beginning of file: lib/src/theme/material_theme/material_tokens.dart + +class MaterialTextThemeTokens +- Unknown displayLarge +- Unknown displayMedium +- Unknown displaySmall +- Unknown headlineLarge +- Unknown headlineMedium +- Unknown headlineSmall +- Unknown titleLarge +- Unknown titleMedium +- Unknown titleSmall +- Unknown bodyLarge +- Unknown bodyMedium +- Unknown bodySmall +- Unknown labelLarge +- Unknown labelMedium +- Unknown labelSmall +- Unknown headline1 +- Unknown headline2 +- Unknown headline3 +- Unknown headline4 +- Unknown headline5 +- Unknown headline6 +- Unknown subtitle1 +- Unknown subtitle2 +- Unknown bodyText1 +- Unknown bodyText2 +- Unknown caption +- Unknown button +- Unknown overline +class MaterialColorSchemeTokens +- Unknown primary +- Unknown secondary +- Unknown tertiary +- Unknown surface +- Unknown background +- Unknown error +- Unknown onPrimary +- Unknown onSecondary +- Unknown onTertiary +- Unknown onSurface +- Unknown onBackground +- Unknown onError +class MaterialTokens +- Unknown textTheme +- Unknown colorScheme + +Beginning of file: lib/src/theme/material_theme/color_scheme_tokens.dart + +class $MDColorScheme +- Unknown primary +- Unknown secondary +- Unknown tertiary +- Unknown surface +- Unknown background +- Unknown error +- Unknown onPrimary +- Unknown onSecondary +- Unknown onTertiary +- Unknown onSurface +- Unknown onBackground +- Unknown onError +- get MixColorTokens tokens + +Beginning of file: lib/src/theme/material_theme/text_theme_tokens.dart + +class $M3Text +- Unknown displayLarge +- Unknown displayMedium +- Unknown displaySmall +- Unknown headlineLarge +- Unknown headlineMedium +- Unknown headlineSmall +- Unknown titleLarge +- Unknown titleMedium +- Unknown titleSmall +- Unknown bodyLarge +- Unknown bodyMedium +- Unknown bodySmall +- Unknown labelLarge +- Unknown labelMedium +- Unknown labelSmall +- get MixTextStyleTokens tokens +class $M2Text +- Unknown headline1 +- Unknown headline2 +- Unknown headline3 +- Unknown headline4 +- Unknown headline5 +- Unknown headline6 +- Unknown subtitle1 +- Unknown subtitle2 +- Unknown bodyText1 +- Unknown bodyText2 +- Unknown caption +- Unknown button +- Unknown overline +- get MixTextStyleTokens tokens + +Beginning of file: lib/src/theme/mix_theme.dart + +class MixTheme extends InheritedWidget +- MixThemeData of(BuildContext context) +- MixThemeData? maybeOf(BuildContext context) +- MixThemeData data +- bool updateShouldNotify(MixTheme oldWidget) +class MixThemeData with Comparable +- MixSpaceTokens space +- MixBreakpointsTokens breakpoints +- MixColorTokens colors +- MixTextStyleTokens textStyles +- MixThemeData copyWith() +- get null props +class BuildContextResolver +- BuildContext context +- get MixThemeData theme +- get TextDirection directionality +- Color color(ColorToken token) +- TextStyle textStyle(TextStyleToken token) +- double space(double value) + +Beginning of file: lib/src/theme/token_alias.dart + +class _SpaceTokensRef +- Unknown instance +- Unknown xsmall +- Unknown small +- Unknown medium +- Unknown large +- Unknown xlarge +- Unknown xxlarge + +Beginning of file: lib/src/theme/tokens/text_style_token.dart + +class TextStyleToken extends TextStyle +- String name +- bool ==(Object other) +- get int hashCode + +Beginning of file: lib/src/theme/tokens/color_token.dart + +class ColorSwatchToken extends ColorSwatch +- String name +- bool ==(Object other) +- get int hashCode +class ColorToken extends Color +- String name +- bool ==(Object other) +- get int hashCode + +Beginning of file: lib/src/theme/tokens/mix_token.dart + +class MixToken +- String name +- bool ==(Object other) +- get int hashCode +- get double ref +- double call() + +Beginning of file: lib/src/theme/tokens/breakpoints.dart + +class MixBreakpointsTokens +- double xsmall +- double small +- double medium +- double large +- ScreenSizeToken getScreenSize(BuildContext context) +- MixBreakpointsTokens copyWith() +- bool ==(Object other) +- String toString() +- get int hashCode + +Beginning of file: lib/src/theme/tokens/radii_token.dart + +class RadiiToken extends MixToken with WithReferenceMixin + +Beginning of file: lib/src/theme/tokens/space_token.dart + +class SpaceTokens +- Unknown xsmall +- Unknown small +- Unknown medium +- Unknown large +- Unknown xlarge +- Unknown xxlarge +- get MixSpaceTokens tokens +class SpaceToken extends MixToken with WithReferenceMixin +class WrapWithSpaceTokens +- T Function(double value) _fn +- get T xsmall +- get T small +- get T medium +- get T large +- get T xlarge +- get T xxlarge +- get T md +- get T sm +- get T lg +- get T xl +- get T xs +- get T xxl +- T call(double value) + +Beginning of file: lib/src/deprecated_alias.dart + +class LegacyTextStyleUtility +- TextStyle textShadow(List shadows) +- TextStyle fontWeight(FontWeight weight) +- TextStyle textBaseline(TextBaseline baseline) +- TextStyle letterSpacing(double spacing) +- TextStyle debugLabel(String label) +- TextStyle textHeight(double height) +- TextStyle wordSpacing(double spacing) +- TextStyle fontStyle(FontStyle style) +- TextStyle fontSize(double size) +- TextStyle inherit(bool value) +- TextStyle textColor(Color color) +- TextStyle textBgColor(Color backgroundColor) +- TextStyle textForeground(Paint foreground) +- TextStyle textBackground(Paint background) +- TextStyle fontFeatures(List features) +- TextStyle textDecoration(TextDecoration decoration) +- TextStyle textDecorationColor(Color decorationColor) +- TextStyle textDecorationStyle(TextDecorationStyle decorationStyle) +- TextStyle textDecorationThickness(double decorationThickness) +- TextStyle fontFamilyFallback(List fontFamilyFallback) + +Beginning of file: lib/src/helpers/deep_collection_equality.dart + +class DeepCollectionEquality +- bool equals(Object? object1, Object? object2) +- int hash(Object? object) +- bool _compareLists(List list1, List list2) +- bool _compareSets(Set set1, Set set2) +- bool _compareMaps(Map map1, Map map2) + +Beginning of file: lib/src/helpers/compare_mixin.dart + +- get List props +- get bool stringify +- bool ==(Object other) +- get int hashCode +- List getDiff(Object other) +- String toString() + +Beginning of file: lib/src/helpers/logger.dart + +class Logger +- String tag +- Unknown stopwatch +- void start() +- void stop() +- void debug(String message) + +Beginning of file: lib/src/helpers/extensions/build_context_ext.dart + +- get MixData? mix +- get TextDirection directionality +- get Orientation orientation +- get Size screenSize +- get Brightness brightness +- get ThemeData theme +- get ColorScheme colorScheme +- get TextTheme textTheme +- get MixThemeData mixTheme +- get bool isDarkMode +- get bool isLandscape +- get bool isPortrait + +Beginning of file: lib/src/helpers/extensions/style_mix_ext.dart + +- StyledContainer container() +- StyledContainer box() +- HBox hbox() +- StyledRow row() +- StyledText text(String text) +- VBox vbox() +- StyledColumn column() +- StyledIcon icon(IconData icon) + +Beginning of file: lib/src/helpers/extensions/string_ext.dart + +- get List words +- get bool isUpperCase +- get bool isLowerCase +- get String camelCase +- get String pascalCase +- get String capitalize +- get String constantCase +- get String snakeCase +- get String paramCase +- get String titleCase +- get String sentenceCase +- get List lowercase +- get List uppercase + +Beginning of file: lib/src/helpers/extensions/helper_ext.dart + +- StrutStyle merge(StrutStyle? other) +- Matrix4 merge(Matrix4? other) +- Iterable sorted() +- T? firstWhereOrNull(bool Function(T) test) + +Beginning of file: lib/src/helpers/attributes_map.dart + +class StylesMap extends MergeableMap +- Unknown empty +- Set buildSpecs(MixData context) +- StylesMap merge(StylesMap? other) +class VariantAttributeMap extends MergeableMap +- Unknown empty +- get List namedVariants +- get List contextVariants +- VariantAttributeMap merge(VariantAttributeMap? other) +class MergeableMap with Comparable +- LinkedHashMap? _map +- get LinkedHashMap map +- get int length +- get bool isEmpty +- get bool isNotEmpty +- get Iterable values +- Iterable whereType() +- Iterable whereRuntimeType() +- LinkedHashMap mergeMap(LinkedHashMap? otherMap) +- MergeableMap merge(MergeableMap? other) +- get List props + +Beginning of file: lib/src/helpers/color_helpers.dart + +- get Color value +- Color darken() +- Color lighten() +- Color fromHex(String hexString) +- String toHex() + +Beginning of file: lib/src/helpers/constants.dart + + +Beginning of file: lib/src/factory/style_group.dart + +class StyleGroup +- StyleGroup merge(StyleGroup? other) +- StyleGroup selectVariants(List variants) +- StyleGroup copyWith() + +Beginning of file: lib/src/factory/mix_provider.dart + +class MixProvider extends InheritedWidget +- MixData? maybeOf(BuildContext context) +- MixData of(BuildContext context) +- MixData? data +- bool updateShouldNotify(MixProvider oldWidget) + +Beginning of file: lib/src/factory/mix_values.dart + +class MixValues with Comparable +- Unknown empty +- StylesMap styles +- VariantAttributeMap variants +- get bool hasVariants +- get bool hasContextVariants +- get bool hasStyles +- get bool hasDecorators +- get bool isEmpty +- get bool isNotEmpty +- get int length +- get List _contextVariants +- get List _decorators +- A? stylesOfType() +- Iterable toValues() +- MixValues copyWith() +- MixValues merge(MixValues? other) +- get null props + +Beginning of file: lib/src/factory/style_mix.dart + +class StyleMix +- Unknown empty +- MixValues _values +- get MixValues values +- Iterable toAttributes() +- StyleMix copyWith() +- StyleMix merge(StyleMix mix) +- StyleMix mergeMany(List mixes) +- StyleMix mergeNullable(StyleMix? style) +- StyleMix selectVariant(Variant variant) +- StyleMix selectVariants(List variants) +- StyleMix pickVariants(List variants) +- StyleMix selectVariantCondition(Map cases) +- bool ==(Object other) +- get int hashCode + +Beginning of file: lib/src/factory/exports.dart + + +Beginning of file: lib/src/factory/mix_provider_data.dart + +class MixData with Comparable +- bool animated +- StylesMap _styles +- BuildContextResolver _resolver +- get BuildContextResolver resolver +- get TextDirection directionality +- get CommonSpec commonSpec +- get List decorators +- List whereDecoratorsOfType() +- A? attributeOf() +- R? maybeGet() +- R get(R defaultValue) +- S spec() +- T dependOnAttributesOf() +- MixData merge(MixData other) +- get null props + +Beginning of file: lib/src/widgets/container_widget.dart + +class StyledContainer extends StyledWidget +- Widget? child +- Widget build(BuildContext context) +class MixedContainer extends StatelessWidget +- Widget? child +- bool animated +- Widget build(BuildContext context) + +Beginning of file: lib/src/widgets/empty_widget.dart + +class Empty extends StatelessWidget +- Widget build(BuildContext context) + +Beginning of file: lib/src/widgets/stack_widget.dart + +class StyledStack extends StyledWidget +- List children +- Widget build(BuildContext context) +class ZBox extends StyledWidget +- List children +- Widget build(BuildContext context) +class MixedStack extends StatelessWidget +- List children +- Widget build(BuildContext context) + +Beginning of file: lib/src/widgets/styled_widget.dart + +class StyledWidgetBuilder +- Widget build(BuildContext context, MixData mix) +class StyledWidget extends StatelessWidget +- StyleMix? _style +- List? _variants +- bool _inherit +- get StyleMix style +- get List? variants +- MixData getMix(BuildContext context) +- Widget withMix(BuildContext context, Widget child) +- Widget withMixBuilder(BuildContext context, WidgetMixBuilder builder) +- void debugFillProperties(DiagnosticPropertiesBuilder properties) +- Widget build(BuildContext context) + +Beginning of file: lib/src/widgets/icon_widget.dart + +class StyledIcon extends StyledWidget +- IconData? icon +- String? semanticLabel +- Widget build(BuildContext context) +class MixedIcon extends StatelessWidget +- IconData? icon +- String? semanticLabel +- Widget build(BuildContext context) + +Beginning of file: lib/src/widgets/pressable/pressable_widget.dart + +class Pressable extends StatefulWidget +- Widget child +- VoidCallback? onPressed +- VoidCallback? onLongPress +- FocusNode? focusNode +- bool autofocus +- Function(bool focus)? onFocusChange +- HitTestBehavior? behavior +- _PressableWidgetState createState() +class _PressableWidgetState extends State +- FocusNode _node +- void initState() +- FocusNode _createFocusNode() +- void didUpdateWidget(Pressable oldWidget) +- void dispose() +- bool _hover +- bool _focus +- bool _pressed +- bool _longpressed +- get bool _onEnabled +- get PressableState _state +- void handleUnpress() +- null updateState(void Function() fn) +- Widget build(BuildContext context) + +Beginning of file: lib/src/widgets/pressable/pressable_state.dart + + +Beginning of file: lib/src/widgets/pressable/pressable.notifier.dart + +class PressableNotifier extends InheritedWidget +- PressableNotifier? of(BuildContext context) +- PressableState state +- bool focus +- bool updateShouldNotify(PressableNotifier oldWidget) + +Beginning of file: lib/src/widgets/mix_context_builder.dart + +class MixBuilder extends StyledWidget +- WidgetMixBuilder _builder +- Widget build(BuildContext context) + +Beginning of file: lib/src/widgets/flex_widget.dart + +class StyledFlex extends StyledWidget +- List children +- Axis direction +- Widget build(BuildContext context) +class FlexBox extends StyledWidget +- List children +- Axis direction +- Widget build(BuildContext context) +class StyledRow extends StyledFlex +class StyledColumn extends StyledFlex +class HBox extends FlexBox +class VBox extends FlexBox +class MixedFlex extends StatelessWidget +- List children +- Axis direction +- List _prepareChildrenWithGap() +- Widget build(BuildContext context) + +Beginning of file: lib/src/widgets/text_widget.dart + +class StyledText extends StyledWidget +- String text +- String? semanticsLabel +- Widget build(BuildContext context) +class MixedText extends StatelessWidget +- String content +- String? semanticsLabel +- void debugFillProperties(DiagnosticPropertiesBuilder properties) +- Widget build(BuildContext context) diff --git a/coverage/lcov.info b/coverage/lcov.info index 3a9eade93..89c06eda7 100644 --- a/coverage/lcov.info +++ b/coverage/lcov.info @@ -1,3227 +1,2674 @@ -SF:lib/src/aliases/box_alias.dart -DA:179,1 -DA:181,1 -DA:184,0 -DA:186,0 -DA:189,0 -DA:191,0 -DA:194,0 -DA:196,0 -DA:199,0 -DA:201,0 -DA:204,0 -DA:206,0 -DA:209,0 -DA:211,0 -DA:214,0 -DA:216,0 -LF:16 -LH:2 -end_of_record -SF:lib/src/aliases/context_variants_alias.dart -DA:4,0 -DA:5,0 -DA:6,0 -DA:7,0 -DA:8,0 -DA:9,0 -DA:10,6 -DA:11,0 -DA:12,0 -DA:13,0 -DA:15,0 -DA:16,3 -DA:17,3 -DA:18,0 -DA:19,0 -DA:21,0 -DA:22,0 -DA:23,0 -DA:26,0 -DA:29,0 -DA:32,0 -DA:35,0 -DA:38,0 -DA:41,0 -DA:44,0 -DA:47,0 -DA:50,0 -DA:53,0 -DA:56,0 -DA:59,0 -DA:62,0 -LF:31 -LH:3 -end_of_record -SF:lib/src/aliases/text_alias.dart -DA:24,0 -DA:25,0 -DA:26,0 -DA:27,0 -DA:28,0 -LF:5 -LH:0 -end_of_record -SF:lib/src/helpers/equatable_mixin.dart -DA:5,1 -DA:6,4 -DA:11,7 -DA:14,7 -DA:15,14 -DA:17,13 -DA:18,7 -DA:19,7 -DA:21,13 -DA:22,6 -DA:23,14 -DA:24,3 -DA:25,19 -DA:27,7 -DA:35,7 -DA:36,7 -DA:41,1 -DA:42,1 +SF:lib/src/core/equality/compare_mixin.dart +DA:5,2 +DA:6,8 +DA:11,23 +DA:14,23 +DA:15,46 +DA:17,37 +DA:18,23 +DA:19,23 +DA:21,28 +DA:22,5 +DA:23,45 +DA:24,2 +DA:25,66 +DA:27,22 +DA:35,23 +DA:36,23 +DA:41,2 +DA:42,2 DA:43,1 DA:44,5 DA:45,2 DA:46,4 -DA:51,1 +DA:51,2 DA:52,0 -DA:54,1 +DA:54,2 DA:55,2 DA:56,2 DA:59,2 -DA:62,3 -DA:63,4 -DA:65,2 -DA:68,1 -DA:69,4 -DA:70,2 -DA:72,4 -DA:76,1 -DA:77,5 -DA:88,0 -DA:90,14 -DA:93,12 -DA:94,36 -DA:95,36 -DA:98,0 -DA:99,0 -DA:101,0 -DA:103,0 -DA:104,0 -DA:106,0 -LF:48 -LH:40 -end_of_record -SF:lib/src/attributes/attribute.dart -DA:9,45 -DA:19,45 -LF:2 -LH:2 -end_of_record -SF:lib/src/attributes/shared/common.attributes.dart -DA:13,5 -DA:21,1 -DA:25,1 -DA:26,2 -DA:27,2 -DA:28,2 -DA:29,2 -DA:30,2 -DA:34,1 -DA:35,1 -DA:36,1 -DA:37,1 -DA:38,1 -DA:39,1 -DA:40,1 -LF:15 -LH:15 -end_of_record -SF:lib/src/attributes/shared/common.utilities.dart -DA:6,0 -DA:8,1 -DA:13,1 -DA:18,0 +DA:62,6 +DA:63,8 +DA:65,4 +DA:68,2 +DA:69,8 +DA:70,4 +DA:72,8 +DA:77,2 +DA:78,6 +DA:80,3 +DA:82,5 +DA:83,1 +DA:85,1 +DA:89,2 +DA:91,2 +DA:100,3 +DA:102,32 +DA:105,25 +DA:106,75 +DA:107,75 +DA:110,3 +DA:111,15 +DA:113,0 +DA:114,0 +DA:117,0 +DA:119,0 +DA:120,0 +DA:121,0 +DA:123,0 +DA:124,0 +DA:125,0 +DA:127,0 +DA:128,0 +DA:129,0 +DA:131,0 +DA:132,0 +DA:133,0 +DA:134,0 +DA:138,0 +DA:144,3 +DA:146,12 +LF:69 +LH:51 +end_of_record +SF:lib/src/core/equality/deep_collection_equality.dart +DA:2,51 +DA:3,3 +DA:5,9 +DA:7,3 +DA:8,2 +DA:9,2 +DA:10,1 +DA:11,2 +DA:12,2 +DA:15,1 +DA:18,1 +DA:19,1 +DA:20,3 +DA:21,2 +DA:22,1 DA:23,1 DA:24,1 -DA:26,1 -DA:33,0 -DA:34,0 -DA:41,1 -DA:42,1 -DA:46,0 -DA:47,0 -DA:50,1 -DA:51,1 -LF:15 -LH:9 +DA:26,2 +DA:27,2 +DA:33,1 +DA:36,2 +DA:37,6 +DA:38,2 +DA:39,4 +DA:47,2 +DA:49,6 +DA:51,4 +DA:52,5 +DA:53,6 +DA:64,1 +DA:65,3 +DA:66,2 +DA:67,1 +LF:33 +LH:33 end_of_record -SF:lib/src/attributes/helpers/helper.utils.dart -DA:5,0 -DA:7,1 -DA:8,2 -DA:25,0 -DA:28,0 -DA:30,0 -DA:31,0 -DA:33,0 -DA:38,14 -DA:43,1 -DA:57,1 -DA:58,2 -DA:59,1 -DA:62,2 -LF:14 -LH:8 +SF:lib/src/helpers/extensions/iterable_ext.dart +DA:2,30 +DA:4,1 +DA:5,2 +DA:6,1 +DA:14,2 +DA:15,2 +DA:16,2 +LF:7 +LH:7 end_of_record -SF:lib/src/factory/mix_context_data.dart -DA:11,6 +SF:lib/src/helpers/extensions/string_ext.dart +DA:5,18 +DA:7,12 +DA:8,6 +DA:9,6 +DA:10,6 +DA:14,6 DA:15,6 -DA:21,6 -DA:22,12 +DA:16,6 +DA:17,12 +DA:19,18 +DA:20,6 +DA:21,30 DA:23,12 -DA:24,6 -DA:27,12 -DA:29,6 +DA:27,6 +DA:30,12 +DA:31,12 DA:34,12 -DA:36,6 -DA:41,6 -DA:47,6 -DA:48,6 -DA:49,1 -DA:51,1 -DA:53,1 -DA:59,1 -DA:60,3 -DA:61,0 -DA:65,1 -DA:74,6 -DA:75,12 -DA:78,1 -DA:79,2 +DA:35,6 +DA:42,3 +DA:44,3 +DA:46,2 +DA:47,10 +DA:48,2 +DA:49,6 +DA:52,2 +DA:55,12 +DA:57,3 +DA:58,3 +DA:59,6 +DA:60,6 +DA:62,9 +DA:63,15 +DA:66,4 +DA:68,4 +DA:70,20 +DA:72,2 +DA:73,10 +DA:75,1 +DA:76,2 +DA:77,1 +DA:79,3 DA:81,1 -DA:86,0 -DA:92,2 -DA:94,1 -DA:98,4 -DA:101,1 -DA:103,2 -LF:31 -LH:29 +DA:86,25 +DA:87,5 +LF:44 +LH:44 end_of_record -SF:lib/src/factory/mix_factory.dart -DA:20,23 -DA:26,8 -DA:40,8 -DA:42,16 -DA:43,8 -DA:46,8 -DA:50,9 -DA:51,18 -DA:54,3 -DA:55,3 -DA:59,3 -DA:60,6 -DA:64,16 +SF:lib/src/helpers/extensions/values_ext.dart +DA:17,1 +DA:18,1 +DA:19,1 +DA:20,1 +DA:21,1 +DA:22,1 +DA:23,1 +DA:24,1 +DA:25,1 +DA:26,1 +DA:30,1 +DA:31,1 +DA:32,2 +DA:33,1 +DA:34,2 +DA:35,2 +DA:36,2 +DA:37,2 +DA:38,1 +DA:39,2 +DA:40,1 +DA:41,2 +DA:48,2 +DA:52,4 +DA:56,0 +DA:57,0 +DA:58,0 +DA:59,0 +DA:62,0 +DA:65,0 +DA:66,0 DA:67,0 -DA:70,0 -DA:74,4 -DA:77,6 -DA:79,0 +DA:68,0 +DA:71,0 +DA:74,0 +DA:75,0 +DA:76,0 +DA:77,0 DA:80,0 -DA:86,3 +DA:85,0 +DA:86,0 +DA:87,0 +DA:88,0 DA:89,0 -DA:90,0 -DA:96,6 -DA:97,6 -DA:100,3 -DA:101,1 -DA:103,2 -DA:104,2 -DA:105,2 -DA:106,1 -DA:116,1 -DA:119,1 -DA:120,1 -DA:121,2 -DA:123,2 -DA:128,1 -DA:132,0 -DA:135,0 -DA:136,0 -DA:138,0 -DA:140,0 -DA:141,0 -DA:142,0 -DA:146,0 -DA:149,1 -DA:150,5 -DA:156,1 -DA:172,3 -DA:174,6 -DA:175,6 -DA:178,3 -DA:184,1 -DA:188,4 -DA:191,0 -DA:192,0 -DA:197,0 -DA:199,0 -DA:202,0 -DA:204,0 -DA:207,0 -DA:211,0 -DA:213,0 -DA:216,0 -DA:218,0 -DA:221,0 -DA:223,0 -DA:225,0 -DA:227,0 -DA:230,0 -DA:232,0 -DA:235,0 -DA:239,0 -DA:242,0 -DA:246,0 -DA:249,0 -DA:251,0 -LF:76 -LH:39 -end_of_record -SF:lib/src/factory/mix_values.dart -DA:14,9 -DA:21,9 -DA:22,9 -DA:24,9 -DA:25,9 -DA:26,9 -DA:28,18 -DA:29,9 -DA:30,9 -DA:31,5 -DA:33,5 -DA:34,3 -DA:36,3 -DA:38,0 -DA:39,0 -DA:43,9 -DA:44,9 -DA:50,27 -DA:52,27 -DA:54,36 -DA:56,32 -DA:58,0 -DA:60,2 -DA:61,16 -DA:65,8 -DA:66,16 -DA:70,3 -DA:71,3 -DA:72,6 -DA:73,3 -DA:74,3 -DA:79,4 -DA:84,4 -DA:85,8 -DA:86,12 -DA:87,12 -DA:92,8 -DA:93,8 -DA:95,4 -DA:96,4 -DA:97,4 -DA:98,4 -DA:103,1 -DA:104,1 -DA:105,2 -DA:106,2 -DA:107,2 -DA:112,9 -DA:115,18 -DA:116,9 -DA:117,1 -DA:119,2 -DA:121,9 -DA:127,15 -DA:132,2 -DA:136,2 -DA:137,6 -DA:138,6 -DA:141,1 -DA:143,5 -LF:60 -LH:57 -end_of_record -SF:lib/src/helpers/color_helpers.dart -DA:23,0 -DA:24,0 -DA:47,0 -DA:48,0 -DA:50,0 -DA:51,0 -DA:53,0 -DA:56,0 -DA:57,0 -DA:59,0 -DA:61,0 -DA:63,0 -DA:67,0 -DA:70,0 -DA:71,0 -DA:72,0 -DA:73,0 -DA:74,0 -DA:79,0 -DA:80,0 -DA:81,0 -DA:82,0 -DA:84,0 -DA:85,0 -LF:24 -LH:0 -end_of_record -SF:lib/src/helpers/extensions.dart -DA:15,0 -DA:20,0 -DA:23,0 -DA:26,0 -DA:30,0 -DA:34,0 -DA:37,0 -DA:40,0 -DA:44,3 -DA:47,3 -DA:50,0 -DA:53,0 -DA:56,0 -DA:59,0 -DA:61,0 -DA:62,0 -DA:64,0 -DA:65,0 -DA:67,0 -DA:68,0 -DA:70,0 -DA:71,0 -DA:73,0 -DA:74,0 -DA:76,0 -DA:77,0 -DA:79,0 -DA:80,0 -DA:84,0 -DA:85,0 -DA:86,0 -DA:87,0 -DA:88,0 -DA:89,0 -DA:90,0 -DA:91,0 DA:92,0 DA:93,0 DA:94,0 DA:95,0 +DA:96,0 +DA:99,0 +DA:100,0 +DA:101,0 DA:102,0 DA:103,0 -DA:105,0 -DA:110,1 -DA:111,1 -DA:112,1 +DA:108,0 +DA:109,0 +DA:110,0 +DA:111,0 +DA:112,0 +DA:113,0 +DA:116,0 +DA:117,0 +DA:118,0 DA:119,0 DA:120,0 -DA:121,0 -LF:49 -LH:5 -end_of_record -SF:lib/src/theme/material_theme/color_scheme_tokens.dart -DA:5,0 -DA:31,3 -DA:32,3 -DA:33,0 -DA:34,0 -DA:35,0 -DA:36,0 -DA:37,0 -DA:38,0 -DA:39,0 -DA:40,0 -DA:41,0 -DA:42,0 -DA:43,0 -DA:44,0 -LF:15 -LH:2 -end_of_record -SF:lib/src/theme/material_theme/material_tokens.dart -DA:5,14 -DA:70,14 -DA:111,0 -LF:3 -LH:2 +DA:123,0 +DA:124,0 +DA:125,0 +DA:126,0 +DA:127,0 +DA:132,0 +DA:133,0 +DA:135,0 +DA:136,0 +DA:138,0 +DA:141,0 +DA:142,0 +DA:144,0 +DA:146,0 +DA:148,0 +DA:152,0 +DA:153,0 +DA:154,0 +DA:156,0 +DA:160,0 +DA:161,0 +DA:162,0 +DA:163,0 +DA:164,0 +DA:166,18 +DA:171,0 +DA:172,0 +DA:173,0 +DA:174,0 +DA:176,0 +DA:181,2 +DA:182,1 +DA:183,1 +DA:184,2 +DA:185,5 +DA:190,16 +DA:194,2 +DA:195,6 +DA:199,4 +DA:200,2 +DA:201,2 +DA:202,2 +DA:203,2 +DA:209,2 +DA:214,1 +DA:215,1 +DA:219,2 +DA:223,2 +DA:227,2 +DA:231,2 +DA:235,2 +DA:239,1 +DA:240,1 +DA:245,2 +DA:249,2 +DA:254,2 +DA:259,2 +DA:264,2 +DA:268,2 +DA:269,2 +DA:270,2 +DA:271,2 +DA:272,5 +DA:273,2 +DA:274,2 +DA:279,2 +DA:283,1 +DA:284,2 +DA:285,0 +DA:286,0 +DA:289,0 +DA:294,1 +DA:295,1 +DA:296,1 +DA:297,1 +DA:298,1 +DA:299,1 +DA:305,2 +DA:306,1 +DA:307,1 +DA:308,1 +DA:309,1 +DA:314,2 +DA:318,2 +DA:321,0 +DA:322,0 +DA:324,0 +DA:329,2 +DA:330,2 +DA:331,1 +DA:332,1 +DA:333,1 +DA:338,1 +DA:339,2 +DA:340,0 +DA:341,0 +DA:344,0 +DA:349,0 +DA:350,0 +DA:351,0 +DA:352,0 +DA:357,2 +DA:358,2 +DA:359,1 +DA:360,1 +DA:361,1 +DA:366,2 +DA:367,1 +DA:368,2 +DA:369,1 +DA:370,1 +DA:371,1 +DA:372,1 +DA:373,1 +DA:374,1 +DA:375,1 +DA:376,1 +DA:377,1 +DA:378,1 +DA:379,1 +DA:380,1 +DA:381,1 +DA:382,1 +DA:383,1 +DA:384,1 +DA:385,1 +DA:386,1 +DA:391,2 +DA:392,2 +DA:393,2 +DA:394,2 +DA:395,2 +DA:400,2 +DA:401,2 +DA:402,2 +DA:403,2 +DA:404,2 +LF:202 +LH:119 end_of_record -SF:lib/src/theme/material_theme/text_theme_tokens.dart -DA:8,0 -DA:25,3 -DA:26,3 -DA:27,0 +SF:lib/src/attributes/attribute.dart +DA:10,106 +DA:20,3 +DA:24,3 +DA:25,0 DA:28,0 -DA:29,0 DA:30,0 DA:31,0 DA:32,0 -DA:33,0 DA:34,0 DA:35,0 DA:36,0 DA:37,0 -DA:38,0 DA:39,0 DA:40,0 DA:41,0 -DA:48,0 -DA:64,3 -DA:65,3 -DA:66,0 -DA:67,0 -DA:68,0 -DA:69,0 +DA:44,0 +DA:54,28 +DA:60,9 +DA:62,27 +DA:65,6 +DA:67,6 +DA:69,10 DA:70,0 -DA:71,0 -DA:72,0 -DA:73,0 -DA:74,0 -DA:75,0 -DA:76,0 -DA:77,0 -DA:78,0 -LF:34 -LH:4 -end_of_record -SF:lib/src/theme/mix_theme.dart -DA:10,1 -DA:14,1 -DA:18,3 -DA:19,4 -DA:20,3 -DA:23,0 -DA:24,0 -DA:27,0 -DA:29,0 -DA:41,3 -DA:48,18 -DA:51,3 -DA:57,3 -DA:58,6 -DA:60,6 -DA:61,9 -DA:65,0 -DA:72,0 -DA:73,0 -DA:74,0 -DA:75,0 -DA:76,0 -DA:80,0 -DA:82,0 -DA:85,0 +DA:71,10 +DA:74,8 +DA:75,16 +DA:80,102 +DA:86,15 +DA:88,0 DA:89,0 -DA:90,0 DA:91,0 -DA:92,0 -DA:93,0 DA:94,0 -DA:97,0 -DA:99,0 -DA:100,0 -DA:101,0 -DA:102,0 -DA:103,0 -DA:110,3 -DA:112,0 -DA:113,0 -DA:116,0 -DA:122,0 -DA:123,0 -DA:126,0 -DA:132,3 -DA:133,6 -DA:136,6 -DA:143,4 -DA:146,0 -LF:49 -LH:17 -end_of_record -SF:lib/src/theme/tokens/color_token.dart -DA:7,0 -DA:12,0 -DA:15,0 -DA:16,0 -DA:17,0 -DA:19,0 -DA:20,0 -DA:24,14 -DA:29,0 -DA:32,0 -DA:33,0 -DA:34,0 -DA:36,3 -DA:37,15 -LF:14 -LH:3 -end_of_record -SF:lib/src/theme/tokens/space_token.dart -DA:5,0 -DA:15,6 -DA:16,0 -DA:17,1 -DA:18,1 -DA:19,0 -DA:20,1 -DA:21,1 -DA:35,14 -DA:45,14 -DA:49,9 -DA:51,0 -DA:53,0 -DA:55,0 -DA:57,0 -DA:59,0 -DA:61,0 -DA:63,0 -DA:64,0 -DA:65,0 -DA:66,0 -DA:67,0 -DA:68,0 -DA:69,0 -DA:70,0 -DA:71,0 -DA:72,0 -DA:73,0 -DA:74,0 -LF:29 -LH:8 -end_of_record -SF:lib/src/theme/tokens/mix_token.dart -DA:8,14 -DA:10,3 -DA:13,0 -DA:14,0 -DA:15,0 -DA:17,3 -DA:18,15 -DA:25,15 -DA:26,0 -DA:28,0 -LF:10 -LH:5 -end_of_record -SF:lib/src/theme/tokens/text_style_token.dart -DA:6,14 -DA:11,0 -DA:14,0 -DA:15,0 -DA:16,0 -DA:18,3 -DA:19,15 -LF:7 -LH:3 -end_of_record -SF:lib/src/variants/utilities/context_variant_utilities.dart -DA:13,0 -DA:15,1 -DA:16,0 -DA:17,0 -DA:19,0 -DA:23,0 -DA:24,0 -DA:26,0 -DA:30,0 -DA:31,0 -DA:33,0 -DA:37,0 -DA:38,0 -DA:40,0 -DA:44,1 -DA:45,1 -DA:47,1 -DA:51,0 -DA:52,0 -DA:54,0 -DA:55,0 -DA:60,0 -DA:61,0 -DA:63,0 -DA:64,0 -DA:69,3 -DA:70,3 -DA:72,1 -DA:73,1 -DA:78,0 -DA:79,0 -DA:81,0 -DA:82,0 -DA:87,0 -DA:88,0 -DA:90,0 -DA:91,0 -DA:93,0 -DA:98,1 -DA:99,1 -DA:101,0 -DA:102,0 -DA:104,0 -DA:109,0 -DA:110,0 -DA:112,0 -DA:113,0 -DA:115,0 -DA:120,0 -DA:121,0 -DA:123,0 -DA:124,0 -DA:126,0 -DA:131,1 -DA:132,1 -DA:134,0 -DA:135,0 -DA:137,0 -DA:142,1 -DA:143,1 -DA:146,0 -DA:147,0 -DA:149,0 -DA:150,0 -LF:64 -LH:14 -end_of_record -SF:lib/src/variants/variant.dart -DA:12,6 -DA:15,0 -DA:16,0 -DA:20,0 -DA:21,0 -DA:27,2 -DA:41,2 -DA:43,4 -DA:44,2 -DA:48,4 -DA:51,1 -DA:55,0 -DA:58,0 -DA:59,0 -DA:61,0 -DA:62,0 -LF:16 -LH:7 -end_of_record -SF:lib/src/widgets/box/box.attributes.dart -DA:36,26 -DA:56,5 -DA:75,5 -DA:76,3 -DA:77,4 -DA:78,5 -DA:79,5 -DA:80,5 -DA:81,5 -DA:82,5 -DA:83,5 -DA:84,4 -DA:85,5 -DA:86,5 -DA:87,5 -DA:88,4 -DA:89,5 -DA:90,5 -DA:91,5 -DA:92,5 -DA:96,0 -DA:117,0 -DA:118,0 -DA:119,0 -DA:124,0 -DA:125,0 -DA:126,0 -DA:139,5 -DA:143,5 -DA:145,12 -DA:147,14 -DA:148,12 -DA:149,16 -DA:150,14 -DA:151,10 -DA:153,5 -DA:154,5 -DA:155,5 -DA:156,5 -DA:157,5 -DA:158,5 -DA:159,5 -DA:160,5 -DA:161,5 -DA:162,5 -DA:163,12 -DA:167,4 -DA:168,4 -DA:169,4 -DA:170,4 -DA:171,4 -DA:172,4 -DA:173,4 -DA:174,4 -DA:175,4 -DA:176,4 -DA:177,4 -DA:178,4 -DA:179,4 -DA:180,4 -DA:181,4 -DA:182,4 -DA:183,4 -DA:184,4 -DA:185,4 -LF:65 -LH:58 -end_of_record -SF:lib/src/widgets/box/box.widget.dart -DA:11,3 -DA:21,3 -DA:23,3 -DA:24,3 -DA:25,3 -DA:26,3 -DA:27,3 -DA:28,3 -DA:29,3 -DA:31,3 -DA:34,3 -DA:45,3 -DA:50,3 -DA:55,3 -DA:57,6 -DA:60,3 -DA:62,6 -DA:63,0 -DA:64,0 -DA:65,0 -DA:66,0 -DA:67,0 -DA:68,0 -DA:69,0 -DA:70,0 -DA:71,0 -DA:72,0 -DA:73,0 -DA:74,0 -DA:78,3 -DA:79,6 -DA:80,6 -DA:81,6 -DA:82,6 -DA:83,6 -DA:84,6 -DA:85,6 -DA:86,6 -DA:87,6 -DA:93,6 -DA:94,1 -DA:95,2 -LF:42 -LH:30 -end_of_record -SF:lib/src/widgets/box/box_decorators/aspect_ratio.dart -DA:8,1 -DA:13,0 -DA:15,0 -DA:16,0 -DA:20,1 -DA:22,1 -DA:24,1 -DA:25,0 -DA:26,0 -DA:27,0 -DA:28,0 -DA:29,0 -DA:30,0 -DA:31,0 -DA:39,1 -DA:40,1 -DA:41,1 -DA:47,0 -DA:48,0 -LF:19 -LH:7 -end_of_record -SF:lib/src/widgets/box/box_decorators/clip_decorator.dart -DA:24,14 -DA:30,0 -DA:35,0 -DA:37,0 -DA:39,0 -DA:40,0 -DA:41,0 -DA:42,0 -DA:47,0 -DA:48,0 -DA:49,0 -DA:54,0 -DA:55,0 -DA:56,0 -DA:57,0 -DA:58,0 -DA:59,0 -DA:60,0 -DA:64,0 -DA:65,0 -DA:66,0 -DA:72,0 -DA:73,0 -DA:74,0 -DA:79,0 -DA:82,0 -DA:83,0 -DA:87,0 -DA:93,0 -DA:100,0 -DA:105,0 -DA:108,0 -DA:110,0 -DA:111,0 -DA:112,0 -DA:113,0 -DA:115,0 -DA:121,0 -DA:123,0 -DA:124,0 -DA:125,0 -DA:126,0 -DA:127,0 -DA:132,0 -LF:44 -LH:1 -end_of_record -SF:lib/src/widgets/box/box_decorators/flexible.dart -DA:14,15 -DA:20,1 -DA:22,1 -DA:23,1 -DA:24,2 -DA:28,1 -DA:30,1 -DA:31,1 -DA:32,1 -DA:33,1 -DA:38,0 -DA:39,0 -LF:12 -LH:10 -end_of_record -SF:lib/src/widgets/box/box_decorators/opacity.dart -DA:8,1 -DA:13,0 -DA:15,0 -DA:18,1 -DA:20,1 -DA:22,1 -DA:23,0 -DA:24,0 -DA:25,0 -DA:26,0 -DA:27,0 -DA:31,1 -DA:32,1 -DA:33,1 -DA:39,0 -DA:40,0 -LF:16 -LH:7 -end_of_record -SF:lib/src/widgets/box/box_decorators/rotate.dart -DA:13,1 -DA:18,0 -DA:20,0 -DA:21,0 -DA:25,1 -DA:27,1 -DA:28,1 -DA:29,1 -DA:34,0 -DA:35,0 -LF:10 -LH:5 -end_of_record -SF:lib/src/widgets/box/box_decorators/scale.dart -DA:14,0 -DA:19,0 -DA:21,0 -DA:24,0 -DA:26,0 -DA:27,0 -DA:28,0 -DA:29,0 -DA:30,0 -DA:31,0 -DA:32,0 -DA:33,0 -DA:34,0 -DA:42,0 -DA:43,0 -DA:44,0 -DA:50,0 -DA:51,0 -LF:18 -LH:0 -end_of_record -SF:lib/src/widgets/box/utilities/box_utilities.dart -DA:20,3 -DA:21,3 -DA:22,3 -DA:32,4 -DA:53,4 -DA:54,4 -DA:55,4 -DA:60,4 -DA:61,4 -DA:62,4 -DA:75,1 -DA:76,1 -DA:79,1 -DA:80,1 -DA:81,1 -DA:85,1 -DA:86,2 -DA:89,1 -DA:90,2 -DA:93,1 -DA:94,2 -DA:97,0 -DA:98,0 -DA:99,0 -DA:105,0 -DA:106,0 -DA:107,0 -DA:113,1 -DA:114,1 -DA:115,1 -DA:121,1 -DA:122,1 -DA:123,1 -DA:129,3 -DA:130,6 -DA:133,0 -DA:134,0 -DA:137,0 -DA:143,0 -DA:144,0 -DA:153,1 -DA:154,1 -DA:157,1 -DA:158,2 -DA:161,1 -DA:162,2 -DA:165,1 -DA:166,2 -DA:169,1 -DA:170,2 -DA:173,0 -DA:174,0 -DA:175,0 -DA:181,0 -DA:182,0 -DA:183,0 -DA:189,1 -DA:190,1 -DA:191,1 -DA:197,1 -DA:198,1 -DA:199,1 -DA:205,6 -DA:207,3 -DA:208,3 -DA:213,3 -DA:214,3 -DA:219,1 -DA:220,1 -DA:225,1 -DA:226,1 -DA:231,1 -DA:232,1 -DA:237,2 -DA:238,2 -DA:243,1 -DA:244,1 -DA:247,1 -DA:248,1 -DA:249,1 -DA:250,1 -DA:255,0 -DA:256,0 -DA:259,1 -DA:265,1 -DA:266,1 -DA:267,1 -DA:268,0 -DA:269,0 -DA:271,0 -DA:276,0 -DA:282,0 -DA:283,0 -DA:284,0 -DA:285,0 -DA:287,0 -DA:288,0 -DA:293,0 -DA:297,0 -DA:298,0 -DA:299,0 -DA:300,0 -DA:305,0 -DA:309,0 -DA:310,0 -DA:311,0 -DA:312,0 -DA:317,0 -DA:321,0 -DA:322,0 -DA:323,0 -DA:324,0 -DA:329,0 -DA:333,0 -DA:334,0 -DA:335,0 -DA:336,0 -DA:341,0 -DA:347,0 -DA:348,0 -DA:354,0 -DA:355,0 -DA:356,0 -DA:357,0 -DA:358,0 -DA:359,0 -DA:360,0 -DA:361,0 -DA:362,0 -DA:363,0 -DA:364,0 -DA:366,0 -DA:367,0 -DA:368,0 -DA:371,0 -DA:375,1 -DA:386,0 -DA:388,1 -DA:389,1 -DA:395,1 -DA:398,0 -DA:403,0 -DA:411,0 -DA:416,0 -DA:424,0 -DA:429,0 -DA:437,0 -DA:442,0 -DA:450,0 -DA:455,0 -DA:463,0 -DA:468,0 -DA:476,1 -DA:477,1 -DA:480,0 -DA:481,0 -DA:482,0 -DA:483,0 -DA:488,0 -DA:489,0 -DA:492,1 -DA:493,1 -DA:496,0 -DA:497,0 -DA:501,0 -DA:509,0 -DA:510,0 -DA:522,0 -DA:532,0 -DA:533,0 -DA:546,1 -DA:552,1 -DA:553,1 -DA:559,1 -DA:560,1 -DA:564,1 -DA:565,1 -DA:566,1 -DA:570,1 -DA:571,2 -DA:574,0 -DA:577,0 -DA:578,0 -DA:588,0 -DA:594,0 -DA:595,0 -DA:596,0 -DA:597,0 -LF:188 -LH:86 -end_of_record -SF:lib/src/widgets/flex/flex.attributes.dart -DA:13,2 -DA:22,1 -DA:26,1 -DA:27,2 -DA:28,1 -DA:29,2 -DA:30,2 -DA:31,2 -DA:32,2 -DA:36,1 -DA:37,1 -DA:38,1 -DA:39,1 -DA:40,1 -DA:41,1 -DA:42,1 -DA:43,1 -LF:17 -LH:17 -end_of_record -SF:lib/src/widgets/flex/flex.utils.dart -DA:9,0 -DA:12,0 -DA:13,0 -DA:19,0 -DA:20,0 -DA:26,1 -DA:27,1 -DA:33,0 -DA:34,0 -DA:40,0 -DA:41,0 -DA:47,1 -DA:48,1 -LF:13 -LH:4 -end_of_record -SF:lib/src/widgets/flex/flex.widget.dart -DA:12,0 -DA:25,0 -DA:30,0 -DA:31,0 -DA:32,0 -DA:33,0 -DA:36,0 -DA:37,0 -DA:44,0 -DA:46,0 -DA:47,0 -DA:48,0 -DA:49,0 -DA:50,0 -DA:51,0 -DA:52,0 -DA:53,0 -DA:55,0 -DA:58,0 -DA:59,0 -DA:60,0 -DA:61,0 -DA:62,0 -DA:63,0 -DA:64,0 -DA:65,0 -DA:66,0 -DA:76,0 -DA:82,0 -DA:89,0 -DA:95,0 -LF:31 -LH:0 -end_of_record -SF:lib/src/widgets/icon/icon.attributes.dart -DA:11,3 -DA:16,2 -DA:20,2 -DA:21,3 -DA:22,3 -DA:26,1 -DA:27,1 -DA:28,1 -DA:29,1 -LF:9 -LH:9 -end_of_record -SF:lib/src/widgets/icon/icon.utilities.dart -DA:13,0 -DA:16,0 -DA:17,0 -DA:19,0 -DA:24,1 -DA:25,1 -DA:31,1 -DA:32,1 -DA:33,1 -LF:9 -LH:5 -end_of_record -SF:lib/src/widgets/icon/icon.widget.dart -DA:10,1 -DA:22,1 -DA:24,1 -DA:25,1 -DA:26,1 -DA:27,1 -DA:28,1 -DA:29,1 -DA:30,1 -DA:32,1 -DA:35,1 -DA:43,1 -DA:57,1 -DA:59,2 -DA:62,1 -DA:63,1 -DA:64,2 -DA:65,2 -DA:66,2 -DA:69,2 -DA:70,0 -DA:71,0 -DA:72,0 -DA:73,0 -DA:74,0 -DA:76,0 -DA:79,0 -DA:80,0 -DA:81,0 -DA:82,0 -DA:84,0 -DA:87,0 -DA:88,0 -DA:98,1 -DA:99,1 -LF:35 -LH:22 -end_of_record -SF:lib/src/widgets/image/image.attributes.dart -DA:18,0 -DA:29,0 -DA:33,0 -DA:34,0 -DA:35,0 -DA:36,0 -DA:37,0 -DA:38,0 -DA:39,0 -DA:40,0 -DA:41,0 -DA:45,0 -DA:46,0 -DA:47,0 -DA:48,0 -DA:49,0 -DA:50,0 -DA:51,0 -DA:52,0 -DA:53,0 -DA:54,0 -LF:21 -LH:0 -end_of_record -SF:lib/src/widgets/image/image.utilities.dart -DA:7,0 -DA:10,0 -DA:20,0 -DA:21,0 -DA:29,0 -DA:30,0 -DA:33,0 -DA:34,0 -DA:37,0 -DA:38,0 -DA:41,0 -DA:42,0 -DA:45,0 -DA:46,0 -DA:49,0 -DA:50,0 -DA:53,0 -DA:54,0 -DA:57,0 -DA:58,0 -LF:20 -LH:0 -end_of_record -SF:lib/src/widgets/mix.widget.dart -DA:11,6 -DA:24,10 -DA:25,8 -DA:26,8 -DA:28,6 -DA:29,6 -DA:31,6 -DA:33,1 -DA:36,0 -DA:37,0 -DA:41,6 -DA:43,17 -DA:50,0 -DA:52,0 -DA:54,0 -DA:55,0 -DA:57,0 -DA:58,0 -DA:60,0 -DA:64,0 -DA:65,0 -LF:21 -LH:10 -end_of_record -SF:lib/src/widgets/mix_context_builder.dart -DA:12,6 -DA:22,6 -DA:24,6 -DA:26,6 -DA:28,6 -DA:29,18 -LF:6 -LH:6 -end_of_record -SF:lib/src/widgets/pressable/pressable.widget.dart -DA:7,0 -DA:16,0 -DA:27,0 -DA:29,0 -DA:35,0 -DA:37,0 -DA:38,0 -DA:41,0 -DA:43,0 -DA:44,0 -DA:45,0 -DA:49,0 -DA:51,0 -DA:52,0 -DA:55,0 -DA:56,0 -DA:64,0 -DA:66,0 -DA:67,0 -DA:72,0 -DA:76,0 -DA:80,0 -DA:87,0 -DA:88,0 -DA:89,0 -DA:90,0 -DA:95,0 -DA:96,0 -DA:99,0 -DA:101,0 -DA:102,0 -DA:104,0 -DA:105,0 -DA:106,0 -DA:107,0 -DA:108,0 -DA:109,0 -DA:110,0 -DA:112,0 -DA:113,0 -DA:115,0 -DA:116,0 -DA:118,0 -DA:119,0 -DA:121,0 -DA:122,0 -DA:123,0 -DA:125,0 -DA:126,0 -DA:128,0 -DA:129,0 -DA:131,0 -DA:132,0 -DA:133,0 -DA:134,0 -DA:135,0 -DA:136,0 -DA:137,0 -DA:139,0 -DA:140,0 -DA:142,0 -DA:143,0 -DA:144,0 -DA:145,0 -LF:64 -LH:0 -end_of_record -SF:lib/src/widgets/text/text.attributes.dart -DA:26,18 -DA:42,1 -DA:55,1 -DA:56,1 -DA:71,3 -DA:72,15 -DA:75,3 -DA:79,3 -DA:81,3 -DA:83,3 -DA:84,3 -DA:85,3 -DA:86,3 -DA:87,3 -DA:88,3 -DA:89,3 -DA:91,3 -DA:92,3 -DA:93,3 -DA:97,3 -DA:110,3 -DA:111,9 -DA:112,3 -DA:113,2 -DA:114,3 -DA:115,2 -DA:116,2 -DA:117,3 -DA:118,3 -DA:119,2 -DA:120,2 -DA:121,9 -DA:125,1 -DA:126,1 -DA:127,1 -DA:128,1 -DA:129,1 -DA:130,1 -DA:131,1 -DA:132,1 -DA:133,1 -DA:134,1 -DA:135,1 -DA:136,1 -DA:137,1 -LF:45 -LH:45 -end_of_record -SF:lib/src/widgets/text/text.utilities.dart -DA:12,0 -DA:15,1 -DA:40,0 -DA:43,1 -DA:44,1 -DA:46,2 -DA:48,1 -DA:53,1 -DA:54,1 -DA:62,1 -DA:63,1 -DA:64,1 -DA:67,1 -DA:78,0 -DA:79,0 -DA:82,1 -DA:83,1 -DA:86,0 -DA:87,0 -DA:90,1 -DA:91,1 -DA:94,1 -DA:95,1 +DA:95,0 DA:98,1 -DA:99,1 -DA:102,1 -DA:103,1 -DA:106,1 -DA:107,1 -DA:110,1 -DA:111,1 -DA:114,0 -DA:115,0 -DA:120,0 -DA:122,0 -DA:123,0 -DA:126,0 -DA:127,0 -LF:38 -LH:25 -end_of_record -SF:lib/src/widgets/text/text.widget.dart -DA:11,1 -DA:23,1 -DA:25,1 -DA:26,1 -DA:27,1 -DA:28,1 -DA:29,1 -DA:31,1 -DA:34,1 -DA:35,1 -DA:43,1 -DA:49,1 -DA:56,1 -DA:58,2 -DA:61,3 -DA:63,1 -DA:65,2 -DA:66,2 -DA:67,2 -DA:68,2 -DA:69,2 -DA:70,2 -DA:71,2 -DA:72,2 -DA:73,2 -DA:74,2 -DA:75,2 -DA:76,1 -DA:79,2 -DA:80,0 -DA:81,0 -DA:82,0 -DA:84,0 -DA:85,0 -DA:86,0 -DA:87,0 -DA:88,0 -DA:89,0 -DA:97,0 -DA:99,0 -DA:101,0 -DA:102,0 -DA:104,0 -DA:109,0 -DA:110,0 -DA:112,0 -DA:117,0 -DA:118,0 -DA:120,0 -LF:49 -LH:29 -end_of_record -SF:lib/src/widgets/zbox/zbox.attributes.dart -DA:10,0 -DA:16,0 -DA:21,0 -DA:22,0 -DA:23,0 -DA:24,0 -DA:28,0 -DA:32,0 -DA:33,0 -DA:34,0 -DA:35,0 -DA:39,0 -DA:40,0 -DA:41,0 -DA:42,0 -DA:43,0 -LF:16 -LH:0 -end_of_record -SF:lib/src/widgets/zbox/zbox.utilities.dart -DA:13,0 -DA:16,0 -DA:17,0 -DA:21,0 -DA:22,0 -DA:26,0 -DA:27,0 -LF:7 -LH:0 -end_of_record -SF:lib/src/widgets/zbox/zbox.widget.dart -DA:14,0 -DA:24,0 -DA:26,0 -DA:27,0 -DA:28,0 -DA:29,0 -DA:30,0 -DA:31,0 -DA:32,0 -DA:33,0 -DA:35,0 -DA:38,0 -DA:39,0 -DA:40,0 -DA:41,0 -DA:42,0 -LF:16 -LH:0 -end_of_record -SF:lib/src/widgets/box/utilities/box_decorators_utilities.dart -DA:7,1 -DA:8,1 -DA:9,1 -DA:14,1 -DA:15,1 -DA:16,1 -DA:21,0 -DA:22,0 -DA:28,0 -DA:29,0 -DA:34,1 -DA:35,1 -DA:36,1 -DA:41,0 -DA:42,0 -DA:43,0 -DA:45,0 -DA:50,0 -DA:51,0 -DA:55,0 -DA:56,0 -DA:60,0 -DA:61,0 -DA:66,1 -DA:67,2 -DA:71,1 -DA:72,2 -DA:76,0 -DA:79,0 -DA:82,0 -DA:85,0 -LF:31 -LH:13 -end_of_record -SF:lib/src/widgets/text/text_directives/text_directives.dart -DA:5,17 -DA:7,1 -DA:9,1 -DA:14,17 -DA:16,1 -DA:18,1 -DA:23,16 -DA:25,0 -DA:27,0 -DA:32,17 -DA:34,1 -DA:36,1 -DA:41,14 -DA:42,0 -DA:44,0 -DA:52,17 -LF:16 -LH:12 -end_of_record -SF:lib/src/widgets/text/text_legacy.utilities.dart -DA:13,0 -DA:15,1 -DA:19,2 -DA:22,0 -DA:24,0 -DA:27,0 -DA:29,0 -DA:32,0 -DA:34,0 -DA:37,0 -DA:39,0 -DA:42,0 -DA:44,0 -DA:47,0 -DA:49,0 -DA:52,0 -DA:54,0 -DA:57,0 -DA:59,0 -DA:62,0 -DA:64,0 -DA:67,0 -DA:69,0 -DA:75,0 -DA:77,0 -DA:79,0 -DA:80,0 -DA:84,0 -DA:86,0 -DA:87,0 -DA:91,1 -DA:93,1 -DA:94,1 -DA:98,0 -DA:100,0 -DA:101,0 -DA:105,0 -DA:107,0 -DA:108,0 -DA:112,0 -DA:114,0 -DA:115,0 -DA:119,0 -DA:121,0 -DA:122,0 -DA:126,0 -DA:128,0 -DA:129,0 -DA:133,0 -DA:135,0 -DA:136,0 -DA:140,0 -DA:142,0 -DA:143,0 -DA:147,0 -DA:149,0 -DA:150,0 -DA:154,1 -DA:156,1 -DA:157,1 -DA:161,0 -DA:163,0 -DA:164,0 -DA:168,0 -DA:170,0 -DA:171,0 -DA:175,0 -DA:177,0 -DA:178,0 -DA:182,0 -DA:184,0 -DA:185,0 -DA:189,0 -DA:191,0 -DA:192,0 -DA:196,0 -DA:198,0 -DA:199,0 -DA:203,0 -DA:205,0 -DA:206,0 -DA:210,0 -DA:212,0 -DA:213,0 -DA:217,0 -DA:219,0 -DA:220,0 -DA:224,0 -DA:226,0 -DA:227,0 -DA:234,0 -DA:236,0 -DA:261,0 -DA:262,0 -DA:263,0 -DA:268,0 -DA:269,0 -DA:282,0 -DA:294,0 -DA:296,0 -DA:299,0 -DA:301,0 -DA:304,0 -DA:310,0 -DA:311,0 -LF:105 -LH:8 +DA:103,4 +DA:106,4 +DA:107,4 +LF:37 +LH:18 end_of_record -SF:lib/src/attributes/shared/common.descriptor.dart -DA:14,6 -DA:22,6 -DA:23,6 -DA:24,6 -DA:26,6 -DA:27,4 -DA:28,4 +SF:lib/src/decorators/decorator.dart +DA:7,7 +DA:9,3 +DA:10,6 +DA:20,5 +LF:4 +LH:4 +end_of_record +SF:lib/src/variants/multi_variant.dart +DA:16,3 +DA:18,3 +DA:22,3 +DA:23,15 +DA:24,12 +DA:26,3 DA:29,4 -DA:33,4 -DA:34,4 -DA:38,0 -DA:42,0 +DA:33,2 +DA:34,2 +DA:37,2 +DA:39,8 +DA:41,4 +DA:42,2 DA:43,0 -DA:44,0 -DA:45,0 -DA:46,0 -DA:47,0 -DA:50,0 -DA:52,0 -DA:53,0 -DA:54,0 -DA:55,0 -DA:56,0 -LF:23 -LH:10 +DA:46,2 +DA:47,4 +DA:48,6 +DA:49,0 +DA:52,1 +DA:53,2 +DA:55,3 +DA:57,2 +DA:58,0 +DA:62,4 +DA:63,1 +DA:67,1 +DA:90,1 +DA:93,1 +DA:96,2 +DA:99,0 +DA:100,0 +LF:31 +LH:26 end_of_record -SF:lib/src/factory/mix_context.dart -DA:16,6 -DA:20,6 -DA:29,6 -DA:30,6 -DA:32,6 -DA:40,6 -DA:41,6 -DA:44,0 -DA:50,0 -DA:54,0 -LF:10 -LH:7 +SF:lib/src/attributes/alignment_attribute.dart +DA:13,57 +DA:23,1 +DA:24,4 +DA:56,57 +DA:58,51 +DA:60,1 +DA:62,5 +DA:65,7 +DA:66,21 +DA:108,53 +DA:110,50 +DA:111,1 +DA:112,1 +DA:114,1 +DA:115,2 +DA:116,2 +DA:120,2 +DA:122,6 +LF:18 +LH:18 end_of_record -SF:lib/src/attributes/nested_attribute.dart -DA:6,1 -DA:10,2 -DA:12,0 -DA:16,0 -DA:19,0 -DA:20,0 +SF:lib/src/attributes/border/border_attribute.dart +DA:14,6 DA:22,0 DA:23,0 -LF:8 -LH:2 -end_of_record -SF:lib/src/decorators/decorator.dart -DA:8,15 -DA:23,1 -DA:24,1 -LF:3 -LH:3 -end_of_record -SF:lib/src/decorators/decorator_wrapper.widget.dart -DA:6,1 -DA:10,1 -DA:16,1 -DA:18,1 -DA:20,2 -DA:21,2 -DA:22,1 -DA:24,1 +DA:30,6 +DA:32,1 +DA:33,0 DA:35,1 -DA:39,1 -DA:44,1 -DA:46,2 -DA:48,1 -LF:13 -LH:13 -end_of_record -SF:lib/src/directives/directive_attribute.dart -DA:2,17 -LF:1 -LH:1 -end_of_record -SF:lib/src/dtos/border/border.dto.dart -DA:13,0 -DA:20,4 -DA:27,2 -DA:28,2 -DA:35,2 -DA:40,2 -DA:41,2 -DA:49,0 -DA:50,0 -DA:51,0 -DA:52,0 -DA:53,0 -DA:54,0 -DA:58,6 -DA:60,6 -DA:62,6 -DA:64,6 -DA:66,1 +DA:38,0 +DA:45,2 +DA:50,2 +DA:51,6 +DA:52,6 +DA:53,5 +DA:54,5 +DA:58,4 +DA:60,4 +DA:61,8 +DA:62,8 +DA:63,8 +DA:64,8 DA:68,1 -DA:69,2 -DA:70,2 -DA:71,2 -DA:72,2 -DA:76,0 -DA:82,0 -DA:83,0 +DA:69,5 +DA:76,3 +DA:83,1 DA:84,0 -DA:85,0 DA:86,0 -DA:90,2 -DA:91,10 +DA:89,0 +DA:96,0 +DA:97,0 +DA:98,0 +DA:99,0 DA:100,0 -DA:107,0 -DA:108,0 -DA:109,0 -DA:110,0 -DA:111,0 -DA:112,0 -DA:116,0 -DA:121,0 -DA:124,0 -DA:131,0 -DA:132,0 -DA:139,0 -DA:144,0 -DA:145,0 -DA:153,0 -DA:154,0 +DA:101,0 +DA:105,1 +DA:113,1 +DA:114,3 +DA:115,3 +DA:116,3 +DA:117,3 +DA:121,1 +DA:123,1 +DA:124,2 +DA:125,2 +DA:126,2 +DA:127,2 +DA:131,1 +DA:132,5 +DA:142,7 +DA:149,0 DA:155,0 DA:156,0 DA:157,0 DA:158,0 -DA:162,0 -DA:164,0 -DA:166,0 -DA:168,0 -DA:170,0 -DA:172,0 -DA:173,0 -DA:174,0 -DA:175,0 -DA:176,0 -DA:180,0 -DA:186,0 -DA:187,0 -DA:188,0 -DA:189,0 -DA:190,0 -DA:194,0 -DA:195,0 -LF:70 -LH:18 -end_of_record -SF:lib/src/dtos/color.dto.dart -DA:10,24 -DA:12,7 -DA:15,7 -DA:20,6 -DA:23,5 -DA:25,5 -DA:27,5 -DA:28,0 -DA:31,5 -DA:34,4 -DA:35,8 -LF:11 -LH:10 -end_of_record -SF:lib/src/dtos/border/border_side.dto.dart -DA:13,1 -DA:20,6 -DA:27,1 -DA:28,1 -DA:29,2 -DA:30,1 -DA:31,1 -DA:32,1 -DA:36,1 +DA:159,0 +DA:163,2 +DA:167,1 +DA:168,2 +DA:169,2 +DA:170,2 +DA:171,1 +DA:175,5 +DA:179,5 +DA:180,10 +DA:181,6 +DA:182,7 +DA:183,9 +DA:187,2 +DA:188,10 +LF:68 +LH:49 +end_of_record +SF:lib/src/attributes/border/border_radius_attribute.dart +DA:20,5 +DA:39,1 +DA:40,1 +DA:41,1 DA:42,1 -DA:43,0 -DA:44,0 +DA:43,1 +DA:44,1 DA:45,1 -DA:46,0 +DA:46,1 +DA:47,1 +DA:48,1 +DA:55,5 +DA:62,0 +DA:64,2 +DA:65,1 +DA:72,1 +DA:73,2 +DA:75,2 +DA:76,1 +DA:83,2 +DA:113,2 +DA:121,2 +DA:122,1 +DA:129,1 +DA:133,1 +DA:134,1 +DA:135,2 +DA:136,2 +DA:137,2 +DA:141,4 +DA:143,4 +DA:144,4 +DA:145,4 +DA:146,4 +DA:147,4 +DA:155,4 +DA:162,1 +DA:192,1 +DA:200,1 +DA:201,2 +DA:203,0 +DA:205,2 +DA:206,1 +DA:213,1 +DA:216,0 +DA:223,1 +DA:226,0 +DA:233,1 +DA:239,1 +DA:240,1 +DA:241,2 +DA:242,2 +DA:243,2 +DA:247,3 +DA:249,3 +DA:250,3 +DA:251,3 +DA:252,3 +DA:253,3 +LF:59 +LH:55 +end_of_record +SF:lib/src/attributes/color_attribute.dart +DA:9,16 +DA:11,4 +DA:12,4 +DA:14,12 +DA:16,12 +DA:18,12 +DA:19,0 +DA:26,3 +DA:28,1 +DA:29,1 +DA:34,1 +DA:36,1 +DA:37,1 +LF:13 +LH:12 +end_of_record +SF:lib/src/attributes/constraints_attribute.dart +DA:10,5 +DA:28,5 +DA:37,1 +DA:41,1 +DA:42,2 +DA:43,2 +DA:44,1 +DA:45,2 +DA:46,1 +DA:47,2 +DA:51,2 +DA:55,2 +DA:56,2 +DA:57,1 +DA:58,1 +DA:59,2 +DA:60,2 +DA:61,2 +DA:62,2 +DA:63,2 +DA:67,4 +DA:68,0 +DA:69,0 +DA:75,1 +DA:76,5 +LF:25 +LH:23 +end_of_record +SF:lib/src/attributes/decoration_attribute.dart +DA:16,7 +DA:33,7 +DA:42,2 +DA:46,2 +DA:47,4 +DA:49,4 +DA:50,4 +DA:51,6 +DA:52,6 +DA:53,4 +DA:57,5 +DA:59,5 +DA:60,9 +DA:61,7 +DA:62,6 +DA:63,7 +DA:64,6 +DA:68,1 +DA:69,7 +DA:85,3 +DA:92,1 +DA:96,1 +DA:97,3 +DA:98,2 +DA:99,2 +DA:100,3 +DA:104,1 +DA:106,1 +DA:107,2 +DA:108,2 +DA:109,1 +DA:110,1 +DA:114,1 +DA:115,5 +DA:120,0 +DA:122,0 +DA:124,0 +LF:37 +LH:34 +end_of_record +SF:lib/src/attributes/edge_insets_attribute.dart +DA:20,2 +DA:37,1 +DA:38,7 +DA:43,2 DA:50,1 +DA:52,1 DA:53,1 DA:54,1 DA:55,1 DA:56,1 -DA:57,1 +DA:60,1 +DA:62,1 DA:63,1 +DA:64,1 DA:65,1 -DA:66,2 -DA:67,1 -DA:68,1 -DA:69,3 -DA:73,3 -DA:74,15 -LF:28 -LH:25 +DA:66,1 +DA:74,2 +DA:81,1 +DA:83,1 +DA:84,1 +DA:85,1 +DA:86,1 +DA:87,1 +DA:91,1 +DA:93,1 +DA:94,1 +DA:95,1 +DA:96,1 +DA:97,1 +LF:29 +LH:29 end_of_record -SF:lib/src/dtos/border/box_border.dto.dart -DA:10,4 -DA:19,0 -DA:20,0 -DA:21,0 -DA:23,0 -DA:24,0 -DA:27,0 -DA:28,0 -DA:32,4 -DA:39,0 +SF:lib/src/attributes/scalar_attribute.dart +DA:7,3 +DA:9,1 +DA:10,1 +DA:14,5 +DA:16,1 +DA:17,1 +DA:22,3 +DA:24,1 +DA:25,1 +DA:30,1 +DA:32,1 +DA:34,1 +DA:39,3 +DA:41,1 DA:42,1 -DA:43,1 -DA:45,1 -DA:46,0 -DA:47,0 -DA:48,0 -DA:49,0 -DA:50,0 -DA:54,1 -DA:55,1 -DA:56,1 -DA:57,1 +DA:47,3 +DA:49,1 +DA:51,1 +DA:56,3 DA:58,1 DA:59,1 -DA:63,0 -DA:64,0 -LF:26 -LH:11 -end_of_record -SF:lib/src/dtos/dto.dart -DA:6,59 -LF:1 -LH:1 -end_of_record -SF:lib/src/dtos/edge_insets/edge_insets.dto.dart -DA:12,5 -DA:19,7 -DA:26,7 -DA:32,1 -DA:40,3 -DA:41,3 -DA:42,6 -DA:43,6 -DA:44,6 -DA:45,6 -DA:50,0 -DA:53,0 -DA:56,6 -DA:58,6 -DA:60,6 -DA:62,6 DA:64,3 -DA:70,3 -DA:71,1 -DA:72,1 -DA:73,0 -DA:74,0 -DA:78,4 -DA:82,3 -DA:83,3 -DA:84,3 -DA:85,3 -DA:86,3 -DA:90,3 -DA:92,3 -DA:94,3 -DA:95,6 -DA:96,6 -DA:97,6 -DA:98,6 -DA:102,3 -DA:103,15 -LF:37 -LH:33 -end_of_record -SF:lib/src/dtos/edge_insets/edge_insets_geometry.dto.dart -DA:9,11 -DA:18,0 -DA:19,0 -DA:21,1 -DA:25,1 +DA:66,1 +DA:67,1 +DA:71,7 +DA:73,1 +DA:74,1 +DA:79,1 +DA:81,1 +DA:82,1 +DA:86,1 +DA:88,1 +DA:89,1 +DA:93,1 +DA:95,1 +DA:96,1 +DA:101,2 +DA:103,1 +DA:104,1 +DA:108,1 +DA:110,1 +DA:111,1 +DA:116,1 +DA:118,1 +DA:119,1 +DA:124,3 +DA:126,1 +DA:127,1 +DA:132,7 +DA:134,1 +DA:135,1 +DA:139,2 +DA:141,1 +DA:142,1 +DA:147,3 +DA:149,1 +DA:150,1 +DA:155,2 +DA:157,1 +DA:158,1 +DA:162,2 +DA:164,1 +DA:165,1 +DA:170,3 +DA:172,1 +DA:173,1 +DA:178,3 +DA:180,1 +DA:182,1 +DA:186,2 +DA:188,1 +DA:189,1 +DA:193,2 +DA:195,1 +DA:196,1 +DA:200,3 +DA:202,1 +DA:203,1 +DA:207,1 +DA:209,1 +DA:210,1 +DA:214,3 +DA:216,1 +DA:217,1 +DA:222,2 +DA:224,1 +DA:225,1 +DA:229,2 +DA:231,1 +DA:232,1 +DA:236,1 +DA:238,1 +DA:239,1 +LF:93 +LH:93 +end_of_record +SF:lib/src/attributes/shadow_attribute.dart +DA:13,4 +DA:15,2 +DA:19,2 +DA:20,4 +DA:21,2 +DA:22,2 DA:26,1 -DA:28,0 -DA:29,0 -DA:32,0 -DA:33,0 -DA:37,4 -DA:43,1 -DA:46,0 -DA:49,0 -DA:50,0 -DA:51,0 -DA:52,0 -DA:53,0 -DA:54,0 -DA:57,0 -DA:58,0 -DA:59,0 -DA:60,0 -DA:61,0 -DA:62,0 -DA:66,0 -DA:67,0 -DA:71,0 -DA:72,0 -DA:75,3 -DA:76,3 -LF:31 -LH:8 -end_of_record -SF:lib/src/dtos/edge_insets/edge_insets_directional.dto.dart -DA:14,0 -DA:21,0 -DA:28,0 -DA:29,0 +DA:28,1 +DA:29,1 +DA:30,3 +DA:31,1 +DA:35,0 DA:36,0 -DA:39,0 -DA:46,0 -DA:49,0 -DA:50,0 -DA:51,0 -DA:52,0 -DA:53,0 -DA:57,0 -DA:58,0 -DA:60,0 -DA:61,0 -DA:63,0 -DA:66,0 -DA:69,0 -DA:70,0 -DA:72,0 +DA:42,3 +DA:49,2 +DA:53,2 +DA:55,2 +DA:56,2 +DA:57,2 +DA:58,2 +DA:59,2 +DA:63,1 +DA:65,1 +DA:66,3 +DA:67,1 +DA:68,1 +DA:69,1 DA:73,0 -DA:75,0 -DA:81,0 -DA:82,0 -DA:83,0 -DA:84,0 -DA:85,0 +DA:74,0 +LF:29 +LH:25 +end_of_record +SF:lib/src/attributes/space_attribute.dart +DA:20,6 +DA:38,1 +DA:42,1 +DA:43,2 +DA:44,2 +DA:45,2 +DA:46,2 +DA:47,2 +DA:48,2 +DA:52,3 +DA:54,3 +DA:55,3 +DA:57,3 +DA:58,3 +DA:59,3 +DA:61,3 +DA:62,6 +DA:63,6 +DA:64,6 +DA:65,6 +DA:67,1 +DA:68,1 +DA:69,1 +DA:71,1 +DA:72,2 +DA:73,2 +DA:74,2 +DA:75,2 +DA:78,0 +DA:83,2 +DA:84,14 DA:89,0 -DA:93,0 -DA:94,0 DA:95,0 -DA:96,0 -DA:97,0 -DA:101,0 -DA:103,0 -DA:105,0 -DA:106,0 -DA:107,0 -DA:108,0 -DA:109,0 -DA:113,0 -DA:114,0 -LF:43 -LH:0 +DA:106,6 +DA:119,6 +DA:121,1 +DA:130,1 +DA:131,0 +DA:132,0 +DA:133,1 +DA:134,1 +DA:143,4 +DA:150,1 +DA:159,1 +DA:160,0 +DA:161,0 +DA:162,1 +DA:163,1 +DA:171,6 +DA:184,6 +DA:186,1 +DA:195,1 +DA:196,0 +DA:197,0 +DA:198,1 +DA:199,1 +DA:208,4 +DA:215,1 +DA:224,1 +DA:225,0 +DA:226,0 +DA:227,1 +DA:228,1 +LF:63 +LH:52 end_of_record -SF:lib/src/dtos/radius/border_radius.dto.dart -DA:12,19 -DA:22,0 -DA:23,0 -DA:24,0 -DA:25,0 -DA:26,0 -DA:27,0 -DA:34,16 -DA:35,1 -DA:42,0 -DA:45,0 -DA:52,0 -DA:55,0 -DA:62,3 -DA:63,3 -DA:65,3 -DA:66,3 -DA:68,3 -DA:69,3 -DA:71,3 -DA:72,3 -DA:74,0 -DA:77,0 -DA:80,0 -DA:83,0 +SF:lib/src/attributes/strut_style_attribute.dart +DA:17,4 +DA:28,1 +DA:32,1 +DA:33,2 +DA:34,2 +DA:35,2 +DA:36,1 +DA:37,2 +DA:38,1 +DA:39,1 +DA:40,2 +DA:44,2 +DA:48,2 +DA:49,3 +DA:50,4 +DA:51,2 +DA:52,3 +DA:53,3 +DA:54,3 +DA:55,3 +DA:56,4 +DA:60,1 +DA:61,1 +DA:62,1 +DA:63,1 +DA:64,1 +DA:65,1 +DA:66,1 +DA:67,1 +DA:68,1 +DA:69,1 +LF:31 +LH:31 +end_of_record +SF:lib/src/attributes/style_mix_attribute.dart +DA:8,1 +DA:10,1 +DA:14,4 +DA:17,1 +DA:18,2 +LF:5 +LH:5 +end_of_record +SF:lib/src/attributes/text_style_attribute.dart +DA:37,5 +DA:62,0 +DA:64,1 +DA:68,1 +DA:71,1 +DA:75,1 +DA:76,2 +DA:77,2 +DA:78,1 +DA:79,2 +DA:80,1 +DA:81,1 +DA:82,1 +DA:83,2 +DA:84,2 +DA:85,1 DA:86,1 -DA:88,1 +DA:87,1 DA:89,2 DA:90,1 DA:91,1 DA:92,1 -DA:96,0 -DA:102,0 -DA:103,0 -DA:104,0 -DA:105,0 -DA:106,0 -DA:110,2 -DA:111,10 -LF:39 -LH:19 +DA:93,2 +DA:94,1 +DA:95,1 +DA:96,1 +DA:97,3 +DA:98,2 +DA:99,1 +DA:100,1 +DA:104,3 +DA:107,3 +DA:110,3 +DA:111,6 +DA:112,3 +DA:113,3 +DA:114,3 +DA:115,3 +DA:116,3 +DA:117,3 +DA:118,3 +DA:119,3 +DA:120,3 +DA:121,3 +DA:122,3 +DA:123,3 +DA:124,3 +DA:125,3 +DA:126,4 +DA:127,3 +DA:128,3 +DA:129,3 +DA:130,3 +DA:131,3 +DA:135,1 +DA:136,1 +DA:137,1 +DA:138,1 +DA:139,1 +DA:140,1 +DA:141,1 +DA:142,1 +DA:143,1 +DA:144,1 +DA:145,1 +DA:146,1 +DA:147,1 +DA:148,1 +DA:149,1 +DA:150,1 +DA:151,1 +DA:152,1 +DA:153,1 +DA:154,1 +DA:155,1 +DA:156,1 +DA:157,1 +DA:158,1 +LF:78 +LH:77 end_of_record -SF:lib/src/dtos/radius/border_radius_geometry.dto.dart -DA:10,19 -DA:12,0 -DA:13,0 -DA:14,0 -DA:15,0 -DA:16,0 -DA:17,0 +SF:lib/src/attributes/variant_attribute.dart +DA:14,4 +DA:16,6 DA:18,0 -DA:19,0 +DA:20,0 DA:21,0 -DA:23,0 DA:24,0 -DA:26,0 -DA:27,0 -DA:29,0 -DA:30,0 -DA:34,4 +DA:27,1 +DA:28,3 +DA:33,3 +DA:35,12 +DA:37,0 +DA:39,0 DA:40,0 DA:43,0 -DA:44,0 -DA:45,0 -DA:46,0 DA:47,0 DA:48,0 DA:49,0 -DA:50,0 -DA:51,0 -DA:53,2 -DA:54,1 -DA:56,1 DA:57,1 -DA:58,1 -DA:59,1 -DA:60,1 -DA:61,1 +DA:59,0 +DA:62,1 +DA:63,2 +DA:64,1 DA:65,0 -DA:66,0 +DA:66,1 DA:67,0 -DA:68,0 -DA:69,0 -DA:70,0 -DA:74,0 -DA:75,0 -LF:43 -LH:10 -end_of_record -SF:lib/src/dtos/radius/radius_dto.dart -DA:12,8 -DA:14,14 -DA:15,0 -DA:21,19 -DA:25,0 -DA:26,0 -DA:27,0 -DA:28,0 -DA:32,0 -DA:33,0 -DA:34,0 -DA:38,0 -DA:41,0 -DA:44,1 -DA:46,1 -DA:47,1 -DA:49,1 -DA:53,1 -DA:56,2 -DA:57,6 -LF:20 -LH:10 +DA:70,2 +DA:73,1 +DA:74,2 +DA:76,0 +DA:78,0 +DA:79,0 +DA:82,0 +LF:32 +LH:14 end_of_record -SF:lib/src/dtos/radius/border_radius_directional.dto.dart -DA:13,0 -DA:16,0 -DA:17,0 +SF:lib/src/decorators/default_decorators.dart +DA:8,3 +DA:10,1 +DA:12,2 +DA:15,1 +DA:16,1 DA:18,0 DA:19,0 -DA:20,0 -DA:24,0 -DA:27,0 -DA:30,0 -DA:40,0 -DA:41,0 -DA:48,0 -DA:51,0 -DA:58,0 -DA:61,0 -DA:68,0 -DA:69,0 -DA:71,0 -DA:74,0 -DA:77,0 -DA:78,0 -DA:80,0 -DA:81,0 -DA:83,0 -DA:86,0 -DA:89,0 -DA:90,0 -DA:92,0 -DA:94,0 -DA:95,0 -DA:96,0 -DA:97,0 -DA:98,0 -DA:102,0 -DA:108,0 -DA:109,0 -DA:110,0 -DA:111,0 -DA:112,0 -DA:116,0 -DA:117,0 -DA:118,0 -DA:119,0 -DA:120,0 -DA:121,0 -LF:45 -LH:0 -end_of_record -SF:lib/src/dtos/shadow/box_shadow.dto.dart -DA:10,32 -DA:17,0 -DA:22,0 -DA:23,0 -DA:24,0 -DA:25,0 -DA:26,0 -DA:30,1 +DA:21,1 +DA:23,1 +DA:29,2 +DA:31,1 DA:32,1 -DA:33,2 DA:34,1 -DA:35,1 DA:36,1 -DA:40,0 +DA:37,1 +DA:38,2 +DA:42,1 +DA:44,3 DA:47,0 DA:48,0 -DA:49,0 -DA:50,0 -DA:51,0 -DA:55,0 -DA:57,0 -DA:58,0 -DA:59,0 -DA:60,0 -DA:61,0 -DA:65,1 -DA:66,5 +DA:50,1 +DA:52,1 +DA:53,1 +DA:54,1 +DA:63,1 +DA:68,3 DA:70,1 -DA:71,4 -DA:74,1 +DA:72,2 DA:75,1 -LF:31 -LH:13 +DA:76,1 +DA:78,0 +DA:79,0 +DA:81,1 +DA:82,1 +DA:87,3 +DA:89,1 +DA:91,2 +DA:94,1 +DA:95,1 +DA:97,0 +DA:98,0 +DA:100,1 +DA:101,1 +DA:106,3 +DA:108,1 +DA:110,2 +DA:113,1 +DA:114,1 +DA:116,0 +DA:117,0 +DA:119,1 +DA:120,1 +LF:52 +LH:42 end_of_record -SF:lib/src/helpers/mergeable_list.dart -DA:7,1 -DA:11,0 -DA:13,0 -DA:15,0 -DA:16,0 -DA:17,0 -DA:19,0 -LF:7 -LH:1 +SF:lib/src/decorators/widget_decorator_wrapper.dart +DA:6,0 +DA:12,0 +DA:14,0 +LF:3 +LH:0 end_of_record -SF:lib/src/dtos/shadow/shadow.dto.dart -DA:14,32 -DA:20,0 -DA:21,0 -DA:22,0 -DA:23,0 -DA:24,0 -DA:28,0 +SF:lib/src/deprecations.dart DA:33,0 -DA:36,0 +DA:35,0 DA:38,0 -DA:39,0 DA:40,0 -DA:41,0 -DA:45,0 +DA:43,0 +DA:47,0 DA:50,0 -DA:51,0 DA:52,0 -DA:53,0 -DA:57,0 +DA:55,0 DA:59,0 -DA:60,0 DA:61,0 -DA:62,0 +DA:64,0 DA:66,0 -DA:67,0 -DA:71,0 -DA:72,0 -DA:75,0 +DA:69,0 +DA:73,0 DA:76,0 -LF:29 -LH:1 -end_of_record -SF:lib/src/dtos/text_style.dto.dart -DA:36,4 -DA:62,2 -DA:63,2 -DA:64,0 -DA:67,2 -DA:68,2 -DA:69,2 -DA:70,2 -DA:71,2 -DA:72,2 -DA:73,2 -DA:74,2 -DA:75,2 -DA:76,2 -DA:77,2 -DA:78,4 -DA:79,4 -DA:80,4 -DA:81,2 -DA:82,2 -DA:83,2 -DA:84,2 -DA:85,2 -DA:86,2 -DA:87,2 -DA:88,2 -DA:89,2 -DA:93,1 -DA:94,1 +DA:80,0 +DA:83,0 +DA:85,0 +DA:94,0 +DA:95,0 +DA:96,0 DA:97,0 -DA:99,1 -DA:101,1 -DA:102,1 -DA:103,1 -DA:104,1 -DA:105,1 -DA:106,1 -DA:107,1 -DA:108,2 -DA:109,1 -DA:110,1 -DA:111,2 -DA:112,2 -DA:113,1 -DA:114,1 -DA:115,1 -DA:116,1 -DA:117,1 -DA:118,1 -DA:119,1 -DA:120,1 -DA:121,1 -DA:122,1 -DA:123,1 -DA:128,1 -DA:129,0 -DA:134,0 -DA:140,0 -DA:165,0 -DA:166,0 -DA:167,0 -DA:168,0 -DA:169,0 -DA:170,0 -DA:171,0 -DA:172,0 -DA:173,0 -DA:174,0 -DA:175,0 -DA:176,0 -DA:177,0 -DA:178,0 -DA:179,0 -DA:180,0 -DA:181,0 -DA:182,0 -DA:183,0 -DA:184,0 -DA:185,0 -DA:186,0 -DA:187,0 -DA:188,0 -DA:192,0 -DA:195,0 -DA:196,0 -DA:197,0 -DA:198,0 -DA:199,0 -DA:200,0 -DA:201,0 -DA:202,0 -DA:203,0 -DA:204,0 -DA:205,0 -DA:206,0 -DA:207,0 -DA:208,0 -DA:209,0 -DA:210,0 -DA:211,0 -DA:212,0 -DA:213,0 -DA:214,0 -DA:215,0 -DA:216,0 -DA:217,0 -DA:218,0 +DA:98,0 +DA:99,0 +DA:100,0 +DA:101,0 +DA:102,0 +DA:103,0 +DA:104,0 +DA:105,0 +DA:112,0 +DA:115,0 +DA:118,0 +DA:121,0 +DA:124,0 +DA:127,0 +DA:130,0 +DA:133,0 +DA:136,0 +DA:139,0 +DA:142,0 +DA:145,0 +DA:148,0 +DA:156,0 +DA:158,0 DA:222,0 DA:223,0 -DA:224,0 -DA:225,0 DA:226,0 DA:227,0 -DA:228,0 -DA:229,0 DA:230,0 DA:231,0 -DA:232,0 -DA:233,0 DA:234,0 DA:235,0 -DA:236,0 -DA:237,0 DA:238,0 DA:239,0 -DA:240,0 -DA:241,0 DA:242,0 DA:243,0 -DA:244,0 -DA:245,0 DA:246,0 -LF:132 -LH:53 -end_of_record -SF:lib/src/variants/variant_attribute.dart -DA:10,5 -DA:18,4 -DA:20,0 -DA:22,0 -DA:23,0 -DA:30,0 -DA:31,0 -DA:32,0 -DA:36,0 -DA:37,0 -DA:39,1 -DA:43,0 -DA:44,0 -DA:45,0 -DA:48,0 -DA:49,0 -DA:53,3 -DA:56,3 -DA:61,1 -DA:62,3 -LF:20 -LH:7 +DA:247,0 +DA:250,0 +DA:251,0 +DA:254,0 +DA:255,0 +DA:258,0 +DA:259,0 +DA:262,0 +DA:263,0 +DA:266,0 +DA:267,0 +DA:270,0 +DA:271,0 +DA:274,0 +DA:275,0 +DA:278,0 +DA:279,0 +DA:282,0 +DA:283,0 +DA:286,0 +DA:287,0 +DA:290,0 +DA:291,0 +DA:294,0 +DA:295,0 +DA:298,0 +DA:299,0 +DA:306,0 +DA:307,0 +DA:311,0 +DA:314,0 +DA:317,0 +DA:320,0 +DA:323,0 +DA:326,0 +DA:329,0 +DA:332,0 +DA:335,0 +DA:341,0 +DA:343,0 +DA:345,0 +DA:347,0 +DA:349,0 +DA:351,0 +DA:353,0 +DA:355,0 +DA:357,0 +DA:362,0 +DA:365,0 +DA:376,0 +DA:377,0 +DA:382,0 +DA:384,0 +DA:387,0 +DA:389,0 +DA:392,0 +DA:394,0 +DA:397,0 +DA:399,0 +DA:402,0 +DA:404,0 +DA:407,0 +DA:409,0 +DA:412,0 +DA:414,0 +DA:459,0 +DA:461,0 +DA:464,0 +DA:466,0 +DA:469,0 +DA:471,0 +DA:475,0 +DA:477,0 +DA:481,0 +DA:483,0 +DA:486,0 +DA:488,0 +DA:491,0 +DA:493,0 +DA:496,0 +DA:498,0 +DA:501,0 +DA:503,0 +LF:142 +LH:0 end_of_record -SF:lib/src/helpers/mergeable_map.dart -DA:17,9 -DA:18,18 -DA:19,9 -DA:24,6 -DA:25,12 -DA:28,9 -DA:29,18 -DA:30,9 -DA:31,16 -DA:32,9 -DA:37,24 -DA:41,5 -DA:42,5 -DA:53,5 -DA:56,5 -DA:57,15 -DA:58,15 -DA:59,5 -DA:67,1 -DA:68,1 -DA:69,3 -DA:75,12 -DA:78,6 -DA:81,0 -DA:82,0 -DA:86,0 -DA:90,27 -DA:96,2 -DA:100,2 -DA:101,10 -DA:103,6 -DA:104,14 -DA:117,1 -DA:118,2 -LF:34 -LH:31 +SF:lib/src/directives/directive_attribute.dart +DA:4,3 +LF:1 +LH:1 end_of_record -SF:lib/src/helpers/deep_collection_equality.dart -DA:9,14 -DA:14,3 -DA:18,5 -DA:19,2 -DA:21,2 -DA:22,0 -DA:24,3 -DA:25,1 -DA:29,3 -DA:30,1 -DA:40,0 -DA:42,0 -DA:43,0 -DA:44,0 +SF:lib/src/directives/directives/controllers.dart +DA:19,0 +DA:41,0 DA:46,0 DA:47,0 DA:48,0 -DA:50,0 -DA:51,0 +DA:49,0 DA:52,0 DA:53,0 DA:54,0 +DA:55,0 +DA:56,0 DA:57,0 -DA:66,2 -DA:67,6 -DA:70,6 -DA:71,6 +DA:58,0 +DA:60,0 +DA:64,0 +DA:65,0 +DA:69,0 +DA:70,0 +DA:71,0 +DA:72,0 +DA:76,0 +DA:80,0 +DA:81,0 DA:82,0 DA:83,0 +DA:84,0 +DA:85,0 DA:86,0 DA:88,0 -DA:89,0 -DA:105,1 -DA:106,3 -DA:109,0 -DA:110,0 +DA:92,0 +DA:93,0 +DA:96,0 +DA:97,0 +DA:99,0 +DA:104,0 +DA:105,0 LF:36 -LH:15 +LH:0 end_of_record -SF:lib/src/widgets/box/box.descriptor.dart -DA:33,3 -DA:54,3 -DA:55,3 -DA:56,3 -DA:58,3 -DA:59,5 -DA:60,3 -DA:61,4 -DA:62,5 -DA:63,3 -DA:64,3 -DA:65,4 -DA:66,4 -DA:67,4 -DA:68,3 -DA:69,3 -DA:70,3 -DA:71,3 -DA:72,3 -DA:73,3 +SF:lib/src/directives/text_directive.dart +DA:7,3 +DA:9,2 +DA:10,2 +DA:14,1 +DA:16,1 +DA:17,1 +DA:21,2 +DA:23,1 +DA:24,1 +DA:28,1 +DA:30,1 +DA:31,1 +DA:35,1 +DA:36,1 +DA:37,1 +DA:41,3 +DA:46,0 +DA:47,0 +DA:52,4 +DA:54,1 +DA:56,1 +DA:63,4 +DA:68,2 +DA:69,2 +DA:71,1 DA:74,3 -DA:76,5 -DA:81,8 -DA:83,3 -DA:85,3 -DA:86,3 -DA:87,3 -DA:88,2 -DA:89,2 -DA:90,2 -DA:91,2 -DA:92,2 -DA:93,2 -DA:94,2 -DA:98,2 -DA:99,1 -DA:100,1 -DA:105,3 -DA:106,1 -DA:107,1 -DA:117,3 -DA:120,3 -DA:121,2 -DA:122,2 -DA:123,2 -DA:124,2 -DA:125,2 -DA:126,2 -DA:127,2 -DA:128,2 -DA:135,0 -DA:139,0 -DA:140,0 -DA:141,0 -DA:142,0 -DA:143,0 -DA:144,0 -DA:145,0 -DA:146,0 -DA:147,0 -DA:148,0 -DA:149,0 -DA:150,0 -DA:151,0 -DA:152,0 -DA:153,0 -DA:154,0 -DA:155,0 -DA:160,0 -DA:161,0 -DA:164,0 -DA:166,0 -DA:167,0 -DA:168,0 -DA:169,0 -DA:170,0 -DA:171,0 -DA:172,0 -DA:173,0 -DA:174,0 -DA:175,0 -DA:176,0 -DA:177,0 -DA:178,0 -DA:179,0 -DA:180,0 -DA:181,0 -DA:182,0 -DA:188,0 -DA:190,0 -DA:191,0 -DA:192,0 -DA:193,0 -DA:194,0 -DA:195,0 -DA:196,0 -DA:197,0 -DA:198,0 -DA:199,0 -DA:200,0 -DA:201,0 -DA:202,0 -DA:203,0 -DA:204,0 -DA:205,0 -DA:206,0 -LF:106 -LH:50 +DA:76,1 +DA:79,1 +DA:80,2 +LF:29 +LH:27 end_of_record -SF:lib/src/widgets/flex/flex.descriptor.dart -DA:14,0 -DA:23,0 -DA:24,0 -DA:25,0 -DA:27,0 -DA:28,0 -DA:30,0 -DA:32,0 -DA:33,0 -DA:35,0 +SF:lib/src/factory/mix_provider.dart +DA:21,3 +DA:27,3 +DA:28,5 DA:36,0 +DA:37,0 DA:40,0 -DA:44,0 -DA:45,0 -DA:46,0 -DA:47,0 -DA:48,0 DA:49,0 -DA:50,0 DA:53,0 -DA:55,0 -DA:56,0 -DA:57,0 -DA:58,0 -DA:59,0 -DA:60,0 -LF:26 +DA:56,3 +DA:62,3 +DA:64,2 +DA:66,2 +DA:70,6 +LF:13 +LH:8 +end_of_record +SF:lib/src/factory/mix_provider_data.dart +DA:25,31 +DA:31,31 +DA:32,31 +DA:34,31 +DA:35,31 +DA:36,31 +DA:43,14 +DA:48,1 +DA:49,1 +DA:54,1 +DA:55,3 +DA:61,9 +DA:62,18 +DA:65,8 +DA:66,16 +DA:74,3 +DA:75,3 +DA:76,3 +DA:77,9 +DA:84,0 +DA:85,0 +DA:88,31 +DA:93,62 +DA:95,62 +DA:96,62 +DA:99,31 +DA:100,31 +DA:103,2 +DA:104,3 +DA:107,1 +DA:108,0 +DA:111,1 +LF:32 +LH:29 +end_of_record +SF:lib/src/factory/style_group.dart +DA:4,0 +LF:1 LH:0 end_of_record -SF:lib/src/widgets/icon/icon.props.dart -DA:10,15 -DA:15,1 -DA:16,1 -DA:17,1 -DA:26,1 -DA:28,1 +SF:lib/src/factory/style_mix.dart +DA:31,84 +DA:47,12 +DA:69,12 +DA:72,12 +DA:74,12 +DA:86,35 +DA:87,35 +DA:88,35 +DA:90,48 +DA:91,13 +DA:92,13 +DA:93,3 +DA:94,2 +DA:95,2 +DA:96,3 +DA:97,3 +DA:99,2 +DA:103,35 +DA:114,1 +DA:131,1 +DA:132,1 +DA:134,3 +DA:156,1 +DA:162,8 +DA:165,5 +DA:168,2 +DA:173,3 +DA:200,1 +DA:201,2 +DA:207,3 +DA:211,3 +DA:212,0 +DA:213,0 +DA:223,4 +DA:226,9 +DA:227,9 +DA:229,3 +DA:258,1 +DA:260,1 +DA:265,1 +DA:266,1 +DA:270,1 +DA:275,2 +DA:276,1 +DA:277,1 +DA:279,1 +DA:284,2 +DA:287,2 +DA:288,1 +DA:290,1 +DA:295,1 +DA:296,1 +DA:301,1 +DA:307,5 +DA:310,1 +DA:313,1 +DA:339,1 +DA:343,1 +DA:347,2 +DA:348,2 +DA:349,1 +DA:352,2 +DA:357,4 +DA:359,1 +DA:385,1 +DA:386,1 +DA:388,2 +DA:389,1 +DA:390,2 +DA:394,1 +DA:397,4 +DA:401,4 +DA:402,12 +DA:403,9 +DA:406,1 +DA:407,5 +DA:414,1 +LF:77 +LH:75 +end_of_record +SF:lib/src/helpers/extensions/build_context_ext.dart +DA:8,2 +DA:13,2 +DA:16,2 +DA:19,0 +DA:22,3 +DA:25,2 +DA:28,3 +DA:31,3 +DA:34,2 +DA:37,3 +DA:40,3 +DA:43,3 +LF:12 +LH:11 +end_of_record +SF:lib/src/helpers/extensions/style_mix_ext.dart +DA:12,1 +DA:18,1 +DA:19,1 +DA:26,1 +DA:33,1 +DA:41,1 +DA:48,1 +DA:49,1 +DA:56,1 +DA:63,1 +DA:64,1 +DA:71,1 +DA:79,1 +DA:82,1 +DA:88,1 +DA:95,1 +DA:96,1 +DA:103,1 +DA:110,1 +DA:111,1 +DA:118,1 +DA:125,1 +DA:127,1 +LF:23 +LH:23 +end_of_record +SF:lib/src/specs/container_spec.dart +DA:21,4 +DA:31,4 +DA:32,4 +DA:33,4 +DA:34,4 +DA:35,4 +DA:36,4 +DA:37,4 +DA:38,4 +DA:39,4 +DA:43,1 +DA:55,1 +DA:56,1 +DA:57,1 +DA:58,1 +DA:59,1 +DA:60,1 +DA:61,1 +DA:62,1 +DA:66,1 +DA:68,1 +DA:69,3 +DA:70,3 +DA:71,3 +DA:72,3 +DA:73,3 +DA:74,4 +DA:75,2 +DA:79,0 +DA:80,0 +DA:81,0 +DA:82,0 +DA:83,0 +DA:84,0 +DA:85,0 +DA:86,0 +DA:87,0 +LF:37 +LH:28 +end_of_record +SF:lib/src/specs/flex_spec.dart +DA:17,3 +DA:28,2 DA:29,2 +DA:31,2 +DA:33,2 +DA:34,2 +DA:36,2 +DA:37,2 +DA:38,2 +DA:39,2 +DA:40,2 +DA:44,1 +DA:46,1 +DA:47,3 +DA:48,3 +DA:49,3 +DA:50,3 +DA:51,3 +DA:52,3 +DA:53,3 +DA:54,3 +DA:58,1 +DA:69,1 +DA:70,0 +DA:71,0 +DA:72,0 +DA:73,0 +DA:74,0 +DA:75,0 +DA:76,0 +DA:77,0 +DA:81,1 +DA:82,1 +DA:83,1 +DA:84,1 +DA:85,1 +DA:86,1 +DA:87,1 +DA:88,1 +DA:89,1 +DA:90,1 +LF:41 +LH:33 +end_of_record +SF:lib/src/specs/icon_spec.dart +DA:14,3 +DA:20,2 +DA:21,2 +DA:22,2 +DA:23,2 +DA:24,2 +DA:28,1 DA:30,1 -DA:37,0 -DA:41,0 +DA:31,3 +DA:32,3 +DA:33,3 +DA:37,1 +DA:43,1 DA:44,0 DA:45,0 -LF:12 -LH:8 +DA:46,1 +DA:50,0 +DA:51,0 +LF:18 +LH:14 end_of_record -SF:lib/src/widgets/image/image.props.dart -DA:19,0 +SF:lib/src/specs/image_spec.dart +DA:18,0 +DA:26,0 +DA:27,0 +DA:28,0 +DA:29,0 DA:30,0 DA:31,0 DA:32,0 -DA:34,0 DA:36,0 -DA:37,0 DA:38,0 DA:39,0 DA:40,0 DA:41,0 DA:42,0 DA:43,0 -DA:44,0 -DA:48,0 -DA:52,0 -DA:53,0 -DA:54,0 -DA:55,0 +DA:47,0 DA:56,0 DA:57,0 DA:58,0 DA:59,0 DA:60,0 -DA:63,0 +DA:61,0 DA:65,0 DA:66,0 -DA:67,0 -DA:68,0 -DA:69,0 -DA:70,0 -DA:71,0 -DA:72,0 -DA:75,0 -DA:77,0 -LF:35 +LF:24 LH:0 end_of_record -SF:lib/src/widgets/text/text.descriptor.dart -DA:24,1 -DA:38,1 -DA:39,1 -DA:40,1 -DA:44,4 -DA:45,2 +SF:lib/src/specs/stack_spec.dart +DA:14,3 +DA:21,2 +DA:22,2 +DA:23,2 +DA:24,2 +DA:25,2 +DA:26,2 +DA:30,1 +DA:32,1 +DA:33,3 +DA:34,2 +DA:35,2 +DA:36,2 +DA:40,1 +DA:47,1 +DA:48,0 +DA:49,0 +DA:50,0 +DA:51,0 +DA:55,1 +DA:56,5 +LF:21 +LH:17 +end_of_record +SF:lib/src/specs/text_spec.dart +DA:23,3 +DA:37,2 +DA:38,2 +DA:39,2 +DA:40,2 +DA:41,2 +DA:42,2 +DA:43,2 +DA:44,2 +DA:45,2 +DA:47,2 +DA:48,2 +DA:49,2 +DA:50,3 +DA:54,2 +DA:58,3 +DA:59,1 +DA:65,1 +DA:69,1 +DA:70,3 +DA:71,3 +DA:72,3 +DA:74,3 +DA:75,3 +DA:76,3 +DA:77,3 +DA:78,3 +DA:79,3 +DA:80,3 +DA:81,3 +DA:85,1 +DA:99,1 +DA:100,0 +DA:101,0 +DA:102,0 +DA:103,0 +DA:104,0 +DA:105,0 +DA:106,0 +DA:107,0 +DA:108,0 +DA:109,0 +DA:110,0 +DA:114,1 +DA:115,1 +DA:116,1 +DA:117,1 +DA:118,1 +DA:119,1 +DA:120,1 +DA:121,1 +DA:122,1 +DA:123,1 +DA:124,1 +DA:125,1 +DA:126,1 +LF:56 +LH:45 +end_of_record +SF:lib/src/theme/mix_theme.dart +DA:13,6 +DA:14,6 +DA:16,5 +DA:17,10 +DA:18,3 +DA:21,0 +DA:22,0 +DA:27,0 +DA:28,0 +DA:41,44 +DA:49,39 +DA:50,0 +DA:58,5 +DA:65,5 +DA:66,11 +DA:67,6 +DA:68,10 +DA:69,6 +DA:70,6 +DA:74,0 +DA:81,0 +DA:82,0 +DA:83,0 +DA:84,0 +DA:85,0 +DA:86,0 +DA:90,0 +DA:91,0 +DA:94,15 +DA:95,0 +DA:96,0 +DA:97,0 +DA:98,0 +DA:99,0 +DA:100,0 +DA:104,15 +DA:105,2 +DA:107,2 +DA:109,2 +DA:111,2 +DA:118,31 +DA:120,9 +DA:122,1 +DA:123,5 +DA:127,1 +DA:128,2 +DA:131,0 +DA:136,1 +DA:137,5 +DA:141,1 +DA:142,2 +DA:146,0 +DA:147,0 +DA:153,1 +DA:154,5 +DA:157,1 +DA:158,2 +DA:161,0 +DA:166,0 +DA:167,0 +DA:171,0 +DA:176,3 +DA:177,6 +DA:178,0 +DA:179,0 +DA:182,0 +DA:184,0 +LF:67 +LH:36 +end_of_record +SF:lib/src/theme/tokens/breakpoints.dart +DA:16,50 +DA:22,2 +DA:23,12 +DA:24,4 +DA:25,2 +DA:26,3 +DA:27,2 +DA:28,3 +DA:40,50 +LF:9 +LH:9 +end_of_record +SF:lib/src/theme/tokens/material_tokens.dart +DA:12,4 +DA:17,4 +DA:22,4 +DA:27,4 +DA:32,4 +DA:37,4 +DA:42,4 +DA:47,4 +DA:52,4 +DA:57,4 +DA:62,4 +DA:67,4 +DA:70,1 +DA:79,4 +DA:83,4 +DA:87,4 +DA:91,4 +DA:95,4 +DA:99,4 +DA:103,4 +DA:107,4 +DA:111,4 +DA:115,4 +DA:119,4 +DA:123,4 +DA:127,4 +DA:131,4 +DA:135,4 +DA:140,4 +DA:144,4 +DA:148,4 +DA:152,4 +DA:156,4 +DA:160,4 +DA:164,4 +DA:168,4 +DA:172,4 +DA:176,4 +DA:180,4 +DA:184,4 +DA:188,4 +DA:191,1 +DA:198,1 +LF:43 +LH:43 +end_of_record +SF:lib/src/theme/tokens/mix_token.dart +DA:8,100 +DA:10,3 +DA:14,0 +DA:16,0 +DA:19,6 +DA:20,18 +DA:25,15 +LF:7 +LH:5 +end_of_record +SF:lib/src/theme/tokens/space_token.dart +DA:13,1 +DA:36,50 +DA:38,1 +DA:39,3 +DA:48,2 +DA:50,3 +DA:52,3 +DA:54,3 +DA:56,3 +DA:58,3 +DA:60,3 +DA:62,6 +LF:12 +LH:12 +end_of_record +SF:lib/src/theme/tokens/text_style_token.dart +DA:10,3 +DA:12,1 +DA:16,4 +DA:19,1 +DA:20,2 +DA:28,2 +LF:6 +LH:6 +end_of_record +SF:lib/src/utils/alignment_util.dart +DA:21,2 +DA:24,4 +DA:27,2 +DA:30,2 +DA:33,4 +DA:36,1 +DA:37,1 +DA:40,2 +DA:43,1 +DA:44,1 +DA:47,1 DA:48,1 DA:51,1 DA:52,1 -DA:53,1 -DA:54,1 DA:55,1 DA:56,1 -DA:57,1 -DA:58,1 DA:59,1 -DA:62,1 -DA:66,1 -DA:72,2 -DA:73,1 -DA:79,0 -DA:83,0 -DA:84,0 -DA:85,0 -DA:86,0 -DA:87,0 -DA:88,0 -DA:89,0 -DA:90,0 -DA:91,0 -DA:92,0 -DA:93,0 -DA:94,0 -DA:97,0 -DA:99,0 -DA:100,0 -DA:101,0 -DA:102,0 -DA:103,0 -DA:104,0 -DA:105,0 -DA:106,0 -DA:107,0 -DA:108,0 -DA:109,0 -LF:45 -LH:20 +DA:60,1 +DA:63,1 +DA:64,1 +DA:67,1 +DA:68,1 +DA:71,1 +DA:72,1 +LF:24 +LH:24 +end_of_record +SF:lib/src/utils/border_radius_util.dart +DA:24,1 +DA:25,1 +DA:26,1 +DA:27,1 +DA:28,1 +DA:30,1 +DA:33,1 +DA:39,1 +DA:40,1 +DA:41,1 +DA:42,1 +DA:44,1 +DA:49,1 +DA:50,2 +DA:54,1 +DA:55,2 +DA:59,1 +DA:60,2 +DA:64,1 +DA:65,2 +DA:70,1 +DA:71,2 +DA:75,1 +DA:76,2 +DA:79,1 +DA:80,1 +DA:81,1 +DA:82,1 +DA:86,1 +DA:87,1 +DA:88,1 +DA:89,1 +DA:94,1 +DA:95,2 +DA:99,1 +DA:100,2 +LF:36 +LH:36 +end_of_record +SF:lib/src/utils/border_util.dart +DA:6,2 +DA:12,2 +DA:19,2 +DA:24,0 +DA:30,0 +DA:37,0 +DA:47,1 +DA:53,1 +DA:54,1 +DA:63,1 +DA:69,1 +DA:70,1 +DA:79,1 +DA:85,1 +DA:86,1 +DA:95,1 +DA:101,1 +DA:102,1 +DA:111,0 +DA:117,0 +DA:118,0 +DA:127,0 +DA:133,0 +DA:134,0 +DA:143,1 +DA:149,1 +DA:150,1 +DA:159,1 +DA:165,1 +DA:166,1 +DA:175,1 +DA:179,1 +DA:187,3 +DA:193,3 +DA:194,3 +LF:35 +LH:26 +end_of_record +SF:lib/src/utils/box_constraints_util.dart +DA:5,1 +DA:6,1 +DA:8,1 +DA:9,1 +DA:11,1 +DA:12,1 +DA:14,1 +DA:15,1 +DA:17,1 +DA:18,1 +DA:20,1 +DA:21,1 +LF:12 +LH:12 end_of_record -SF:lib/src/widgets/zbox/zbox.props.dart -DA:11,0 +SF:lib/src/utils/context_variant_util.dart +DA:9,3 +DA:11,3 +DA:13,3 +DA:15,3 DA:17,0 -DA:18,0 -DA:19,0 -DA:21,0 DA:22,0 -DA:23,0 -DA:24,0 DA:28,0 +DA:30,0 +DA:31,0 DA:32,0 DA:33,0 -DA:34,0 DA:35,0 -DA:38,0 -DA:39,0 -DA:41,0 -DA:46,0 -DA:47,0 -DA:48,0 -DA:49,0 -LF:20 -LH:0 +DA:41,3 +DA:43,3 +DA:46,3 +DA:47,3 +DA:51,3 +DA:53,3 +DA:55,1 +DA:56,1 +DA:57,3 +DA:58,3 +DA:62,1 +DA:63,1 +DA:64,3 +DA:65,1 +DA:66,3 +DA:71,1 +DA:72,1 +DA:73,3 +DA:74,1 +DA:75,2 +DA:77,1 +DA:79,1 +DA:82,1 +DA:83,0 +DA:86,2 +DA:91,3 +DA:92,3 +DA:93,6 +DA:94,9 +DA:98,1 +DA:99,1 +DA:100,3 +DA:101,1 +DA:102,2 +LF:46 +LH:37 end_of_record -SF:lib/src/theme/tokens/breakpoints.dart -DA:11,0 -DA:18,14 -DA:26,0 -DA:27,0 -DA:29,0 +SF:lib/src/utils/decoration_util.dart +DA:6,2 +DA:7,4 +LF:2 +LH:2 +end_of_record +SF:lib/src/utils/gradient_util.dart +DA:5,1 +DA:13,1 +DA:15,1 +DA:16,1 +DA:17,1 +DA:18,1 +DA:21,1 +DA:27,1 +DA:37,1 +DA:39,1 +DA:40,1 +DA:41,1 +DA:42,1 +DA:47,1 +LF:14 +LH:14 +end_of_record +SF:lib/src/utils/helper_util.dart +DA:8,99 +DA:10,1 +DA:32,3 +DA:35,1 +LF:4 +LH:4 +end_of_record +SF:lib/src/utils/pressable_util.dart +DA:9,3 +DA:10,3 +DA:11,3 +DA:12,6 +DA:14,8 +DA:16,3 +DA:18,1 +DA:19,1 +DA:21,2 +DA:25,2 +DA:26,2 +DA:27,6 +DA:28,2 +DA:29,2 +DA:31,4 +LF:15 +LH:15 +end_of_record +SF:lib/src/utils/space_util.dart +DA:10,6 +DA:11,3 +DA:12,3 +DA:13,3 +DA:14,4 +DA:15,4 +DA:16,4 +DA:17,4 +DA:18,4 +DA:19,4 +DA:20,4 +DA:21,4 +DA:22,4 +DA:24,1 +DA:25,1 +DA:26,1 +DA:27,1 +DA:28,1 +DA:30,0 DA:31,0 -DA:33,0 -DA:38,0 -DA:44,0 -DA:45,0 -DA:46,0 -DA:47,0 -DA:48,0 -DA:52,0 -DA:56,0 -DA:57,0 -DA:58,0 +DA:39,6 +DA:40,3 +DA:41,3 +DA:42,3 +DA:43,4 +DA:44,4 +DA:45,4 +DA:46,4 +DA:47,4 +DA:48,4 +DA:49,4 +DA:50,4 +DA:51,4 +DA:53,1 +DA:54,1 +DA:55,1 +DA:56,1 +DA:57,1 DA:59,0 DA:60,0 -DA:63,0 -DA:65,0 -DA:68,0 -DA:70,0 -LF:23 -LH:1 +DA:75,49 +DA:77,2 +DA:79,3 +DA:81,3 +DA:82,3 +DA:83,3 +DA:84,3 +DA:86,3 +DA:87,3 +DA:89,1 +DA:90,2 +DA:91,1 +DA:92,1 +DA:93,1 +DA:94,1 +DA:98,2 +DA:112,4 +DA:123,49 +DA:125,2 +DA:127,3 +DA:128,3 +DA:130,1 +DA:131,2 +DA:132,1 +DA:133,1 +DA:134,1 +DA:135,1 +DA:139,1 +DA:154,2 +LF:69 +LH:65 end_of_record -SF:lib/src/theme/tokens/radii_token.dart -DA:6,0 -LF:1 -LH:0 +SF:lib/src/utils/text_util.dart +DA:13,0 +DA:14,0 +DA:17,1 +DA:18,2 +DA:20,2 +DA:41,2 +DA:43,1 +DA:44,2 +DA:47,1 +DA:58,2 +DA:64,2 +DA:66,2 +DA:68,1 +DA:69,1 +DA:70,1 +DA:71,2 +DA:72,1 +DA:76,2 +DA:78,1 +DA:80,2 +LF:20 +LH:18 end_of_record SF:lib/src/variants/context_variant.dart -DA:9,3 -DA:15,3 -DA:21,1 -DA:22,5 -DA:25,3 +DA:16,5 +DA:18,3 DA:41,3 -DA:43,6 DA:44,3 DA:47,6 DA:50,1 -DA:51,1 -DA:52,1 -DA:53,1 -DA:54,1 -DA:58,0 -DA:59,0 -DA:61,0 -DA:65,0 -DA:66,0 -DA:67,0 -DA:70,0 -DA:71,0 -LF:22 -LH:14 -end_of_record -SF:lib/src/widgets/pressable/pressable.notifier.dart -DA:6,0 -DA:11,0 -DA:17,0 -DA:18,0 -DA:21,0 -DA:23,0 -LF:6 -LH:0 +DA:51,3 +LF:7 +LH:7 end_of_record -SF:lib/src/variants/variant_operation.dart -DA:16,0 -DA:21,0 -DA:22,0 -DA:26,0 -DA:31,0 -DA:32,0 -DA:36,0 -DA:41,0 -DA:45,0 -DA:46,0 -DA:47,0 -DA:48,0 -DA:50,0 -DA:54,0 -DA:57,0 -DA:60,0 -DA:61,0 -DA:63,0 -DA:64,0 -DA:69,0 -DA:70,0 -DA:75,0 -DA:82,0 -DA:86,0 -DA:100,0 -DA:101,0 -DA:102,0 -DA:103,0 -DA:104,0 -DA:105,0 -DA:106,0 -DA:107,0 -DA:108,0 -DA:109,0 -DA:110,0 -DA:111,0 -DA:112,0 -DA:114,0 -DA:115,0 -DA:116,0 -DA:117,0 -DA:118,0 -DA:121,0 -DA:124,0 -DA:128,0 -DA:129,0 -DA:130,0 -DA:133,0 -DA:134,0 -DA:136,0 -DA:137,0 -LF:51 -LH:0 +SF:lib/src/variants/variant.dart +DA:16,48 +DA:19,3 +DA:22,3 +DA:27,1 +DA:49,1 +DA:52,1 +DA:56,2 +DA:59,3 +DA:60,6 +LF:9 +LH:9 end_of_record -SF:lib/src/widgets/box/box.decorator.dart -DA:6,15 -DA:8,1 -DA:13,0 -LF:3 -LH:2 +SF:lib/src/widgets/container_widget.dart +DA:11,3 +DA:15,3 +DA:17,6 +DA:18,3 +DA:20,3 +DA:21,3 +DA:22,3 +DA:23,3 +DA:24,3 +DA:25,3 +DA:26,3 +DA:27,3 +DA:28,3 +LF:13 +LH:13 end_of_record -SF:lib/src/widgets/empty.widget.dart -DA:4,42 -DA:6,1 +SF:lib/src/widgets/empty_widget.dart +DA:4,1 +DA:6,0 LF:2 -LH:2 +LH:1 end_of_record -SF:lib/src/widgets/gap/gap_widget.dart -DA:30,0 -DA:35,0 -DA:36,0 -DA:37,0 -DA:43,0 -DA:47,0 -DA:78,0 -DA:83,0 -DA:89,0 -DA:91,0 -DA:93,0 -DA:94,0 -DA:95,0 -DA:96,0 -DA:119,0 -DA:124,0 -DA:132,0 -DA:136,0 -DA:165,0 -DA:167,0 -DA:168,0 -DA:169,0 -DA:170,0 -DA:171,0 -DA:178,0 -DA:184,0 -DA:185,0 -DA:186,0 -DA:196,0 -DA:198,0 -DA:199,0 -DA:200,0 -DA:201,0 -DA:202,0 -DA:206,0 -DA:209,0 -DA:210,0 -DA:211,0 -DA:212,0 -DA:215,0 -DA:217,0 -DA:218,0 -DA:219,0 -DA:221,0 -DA:224,0 -DA:225,0 -LF:46 -LH:0 +SF:lib/src/widgets/flex_widget.dart +DA:8,1 +DA:19,1 +DA:21,2 +DA:22,1 +DA:23,1 +DA:24,1 +DA:25,4 +DA:26,3 +DA:27,4 +DA:35,2 +DA:37,1 +DA:38,1 +DA:39,2 +DA:40,2 +DA:42,2 +DA:43,2 +DA:44,1 +DA:51,1 +DA:56,1 +DA:60,1 +DA:65,1 +DA:69,1 +DA:80,1 +DA:82,2 +DA:83,1 +DA:85,1 +DA:87,1 +DA:88,1 +DA:96,1 +DA:101,1 +DA:105,1 +DA:110,1 +LF:32 +LH:32 end_of_record -SF:lib/src/widgets/gap/gap_rendering.dart -DA:5,0 -DA:15,0 -DA:17,0 -DA:18,0 -DA:19,0 -DA:20,0 -DA:24,0 -DA:26,0 -DA:27,0 -DA:28,0 -DA:29,0 -DA:33,0 -DA:35,0 +SF:lib/src/widgets/icon_widget.dart +DA:7,1 +DA:18,1 +DA:20,2 +DA:22,1 +DA:24,1 +DA:25,1 +DA:26,1 +DA:27,1 +DA:28,1 +DA:29,1 DA:36,0 -DA:37,0 -DA:38,0 -DA:42,0 -DA:43,0 -DA:44,0 -DA:45,0 -DA:47,0 +DA:49,0 DA:51,0 DA:53,0 -DA:54,0 DA:55,0 DA:56,0 +DA:57,0 +DA:58,0 +DA:59,0 DA:60,0 -DA:62,0 -DA:64,0 -DA:68,0 -DA:70,0 -DA:72,0 -DA:76,0 -DA:78,0 -DA:80,0 -DA:84,0 -DA:86,0 -DA:88,0 +DA:61,0 +LF:21 +LH:10 +end_of_record +SF:lib/src/widgets/pressable/pressable.notifier.dart +DA:6,3 +DA:13,3 +DA:14,3 +DA:21,1 +DA:23,6 +LF:5 +LH:5 +end_of_record +SF:lib/src/widgets/pressable/pressable_widget.dart +DA:7,1 +DA:27,1 +DA:30,1 +DA:36,1 +DA:38,1 +DA:39,4 +DA:42,1 +DA:43,4 +DA:46,0 +DA:48,0 +DA:49,0 +DA:50,0 +DA:54,1 +DA:56,4 +DA:57,1 +DA:65,5 +DA:67,1 +DA:68,4 +DA:73,1 +DA:77,1 +DA:81,1 +DA:89,0 +DA:90,0 +DA:91,0 DA:92,0 -DA:93,0 -DA:94,0 -DA:95,0 DA:97,0 DA:98,0 -DA:100,0 -DA:105,0 -DA:107,0 +DA:101,1 +DA:103,1 +DA:104,1 +DA:105,1 +DA:107,3 +DA:108,2 +DA:109,1 DA:110,0 DA:111,0 +DA:112,0 DA:113,0 +DA:114,0 +DA:115,2 DA:116,0 +DA:117,0 +DA:118,2 +DA:119,1 +DA:120,1 +DA:121,1 +DA:122,2 DA:123,0 -DA:125,0 -DA:128,0 -DA:130,0 -DA:131,0 -DA:132,0 -DA:136,0 -DA:138,0 -DA:139,0 -DA:140,0 -DA:141,0 -DA:142,0 -LF:63 -LH:0 +DA:124,0 +DA:125,2 +DA:126,1 +DA:127,1 +DA:128,1 +DA:129,2 +LF:54 +LH:35 end_of_record -SF:lib/src/widgets/text/text_directives/text_directive_helpers.dart -DA:1,1 -DA:3,1 -DA:7,4 -DA:10,0 -DA:13,0 -DA:15,0 -DA:18,1 -DA:21,1 -DA:23,1 -DA:24,2 +SF:lib/src/widgets/stack_widget.dart +DA:8,1 +DA:17,1 +DA:19,2 +DA:20,1 +DA:24,1 +DA:25,1 +DA:26,1 DA:27,1 -LF:11 -LH:8 +DA:28,1 +DA:29,1 +DA:36,1 +DA:45,1 +DA:47,2 +DA:48,1 +DA:50,2 +LF:15 +LH:15 end_of_record -SF:lib/src/aliases/token_alias.dart -DA:4,3 -DA:7,1 -DA:9,3 -DA:11,2 -LF:4 -LH:4 +SF:lib/src/widgets/styled_widget.dart +DA:8,3 +DA:22,3 +DA:23,3 +DA:25,3 +DA:27,3 +DA:36,0 +LF:6 +LH:5 end_of_record -SF:lib/src/extensions/mix_extensions.dart -DA:14,1 -DA:21,1 -DA:22,1 -DA:30,0 -DA:38,0 +SF:lib/src/widgets/text_widget.dart +DA:10,1 +DA:23,1 +DA:25,2 +DA:26,1 +DA:28,1 +DA:29,2 +DA:30,1 +DA:31,1 +DA:32,1 +DA:33,1 +DA:34,1 +DA:35,1 +DA:36,1 +DA:37,1 +DA:38,1 +DA:39,1 +DA:40,1 +DA:41,1 +LF:18 +LH:18 +end_of_record +SF:lib/src/theme/tokens/color_token.dart +DA:10,5 +DA:12,1 +DA:16,4 +DA:19,1 +DA:20,2 +DA:27,2 +LF:6 +LH:6 +end_of_record +SF:lib/src/core/attributes_map.dart +DA:15,31 +DA:17,31 +DA:18,31 +DA:19,40 +DA:20,9 +DA:21,9 +DA:22,6 +DA:24,9 +DA:28,31 +DA:31,9 +DA:33,9 +DA:35,3 +DA:37,0 DA:39,0 -DA:44,0 +DA:41,9 +DA:43,9 +DA:44,36 +DA:46,1 +DA:47,3 +DA:50,3 +DA:51,9 +DA:53,3 +DA:56,0 +DA:57,0 +LF:24 +LH:20 +end_of_record +SF:lib/src/decorators/clip_decorator.dart +DA:11,3 +DA:19,0 +DA:20,0 +DA:30,3 +DA:32,1 +DA:34,1 +DA:35,3 +DA:36,3 +DA:40,1 +DA:45,1 +DA:46,0 +DA:47,0 DA:51,0 DA:52,0 +DA:56,3 +DA:58,1 DA:60,1 -DA:68,1 -DA:70,1 -DA:78,0 -DA:85,0 -DA:86,0 -DA:91,0 -DA:98,0 -DA:104,1 -DA:111,1 -DA:113,1 -LF:20 -LH:9 +DA:61,1 +DA:62,2 +DA:66,2 +DA:68,6 +DA:71,2 +DA:73,2 +DA:74,2 +DA:75,2 +DA:82,3 +DA:84,1 +DA:86,1 +DA:87,1 +DA:88,2 +DA:92,2 +DA:94,2 +DA:95,2 +DA:96,2 +DA:100,2 +DA:102,2 +DA:103,2 +DA:104,2 +DA:113,2 +DA:119,1 +DA:121,1 +DA:122,3 +DA:123,3 +DA:124,3 +DA:128,1 +DA:134,1 +DA:135,0 +DA:136,0 +DA:137,0 +DA:141,0 +DA:142,0 +DA:146,2 +DA:148,1 +DA:150,1 +DA:151,1 +DA:152,2 +DA:156,1 +DA:158,1 +DA:159,1 +DA:160,1 +DA:164,0 +DA:165,0 +DA:167,1 +DA:169,1 +DA:170,1 +DA:171,1 +DA:179,3 +DA:185,1 +DA:187,1 +DA:188,1 +DA:189,1 +DA:190,1 +DA:194,1 +DA:196,1 +DA:197,1 +DA:198,1 +DA:199,1 +DA:203,0 +DA:204,0 +DA:206,1 +DA:208,1 +DA:209,1 +DA:210,1 +DA:211,1 +DA:218,0 +DA:224,0 +DA:226,0 +DA:231,0 +DA:239,0 +DA:241,0 +DA:242,0 +DA:243,0 +DA:244,0 +DA:246,0 +DA:252,50 +DA:253,1 +DA:255,1 +DA:256,3 +DA:257,3 +DA:258,2 +DA:259,1 +DA:264,0 +LF:102 +LH:76 +end_of_record +SF:lib/src/utils/decorators_util.dart +DA:15,2 +DA:16,2 +DA:17,2 +DA:25,1 +DA:30,1 +DA:33,1 +DA:39,1 +DA:40,1 +LF:8 +LH:8 +end_of_record +SF:lib/src/theme/tokens/radius_token.dart +DA:12,1 +DA:24,52 +DA:26,1 +DA:30,4 +DA:33,1 +DA:34,2 +DA:42,1 +DA:51,1 +DA:53,0 +DA:57,0 +DA:60,2 +DA:62,2 +DA:64,2 +DA:66,3 +LF:14 +LH:12 end_of_record diff --git a/demo/analysis_options.yaml b/demo/analysis_options.yaml index d828d7954..49feb998b 100644 --- a/demo/analysis_options.yaml +++ b/demo/analysis_options.yaml @@ -9,22 +9,4 @@ linter: prefer_relative_imports: true analyzer: - plugins: - - dart_code_metrics -dart_code_metrics: - metrics: - cyclomatic-complexity: 20 - number-of-parameters: 4 - maximum-nesting-level: 5 - metrics-exclude: - - test/** - rules: - - newline-before-return - - no-boolean-literal-compare - - no-empty-block - - prefer-trailing-comma - - no-equal-then-else - anti-patterns: - - long-method - - long-parameter-list diff --git a/demo/ios/Runner/Assets.xcassets/LaunchBackground.imageset/Contents.json b/demo/ios/Runner/Assets.xcassets/LaunchBackground.imageset/Contents.json index 9f447e1b3..f2e49c091 100644 --- a/demo/ios/Runner/Assets.xcassets/LaunchBackground.imageset/Contents.json +++ b/demo/ios/Runner/Assets.xcassets/LaunchBackground.imageset/Contents.json @@ -1,21 +1,21 @@ { - "images" : [ + "images": [ { - "filename" : "background.png", - "idiom" : "universal", - "scale" : "1x" + "filename": "background.png", + "idiom": "universal", + "scale": "1x" }, { - "idiom" : "universal", - "scale" : "2x" + "idiom": "universal", + "scale": "2x" }, { - "idiom" : "universal", - "scale" : "3x" + "idiom": "universal", + "scale": "3x" } ], - "info" : { - "author" : "xcode", - "version" : 1 + "info": { + "author": "xcode", + "version": 1 } } diff --git a/demo/lib/components/examples/box/box.mix.dart b/demo/lib/components/examples/box/box.mix.dart index eab3fbc0f..1efc8c8bb 100644 --- a/demo/lib/components/examples/box/box.mix.dart +++ b/demo/lib/components/examples/box/box.mix.dart @@ -2,10 +2,9 @@ import 'package:mix/mix.dart'; StyleMix get button { return StyleMix( - textStyle(as: $M3Text.bodyMedium), + textStyle(as: MaterialTextStyles.bodyMedium), bold(), textStyle(fontSize: 16.0), - animation(), backgroundColor($M3Color.primary), onHover( backgroundColor($M3Color.secondary), diff --git a/demo/lib/components/m2_typography.dart b/demo/lib/components/m2_typography.dart index 0914301b7..c9e4773b5 100644 --- a/demo/lib/components/m2_typography.dart +++ b/demo/lib/components/m2_typography.dart @@ -13,9 +13,9 @@ class M2TokensTypographyExampleTile extends HookWidget { ), ); - final headingMix = StyleMix.fromAttributes([ + final headingMix = StyleMix.create([ textStyle(fontSize: 22), - ...onSurfaceMix.toAttributes(), + ...onSurfaceMix.values, ]); return ExpansionTile( diff --git a/demo/lib/components/m3_typography.dart b/demo/lib/components/m3_typography.dart index 1880ea29e..e4143e361 100644 --- a/demo/lib/components/m3_typography.dart +++ b/demo/lib/components/m3_typography.dart @@ -13,9 +13,9 @@ class M3TokensTypographyExampleTile extends HookWidget { ), ); - final headingMix = StyleMix.fromAttributes([ + final headingMix = StyleMix.create([ textStyle(fontSize: 22), - ...onSurfaceMix.toAttributes(), + ...onSurfaceMix.values, ]); return ExpansionTile( @@ -27,7 +27,7 @@ class M3TokensTypographyExampleTile extends HookWidget { ), tilePadding: const EdgeInsets.all(0), children: [ - ...$M3Text.tokens + ...MaterialTextStyles.tokens .map( (token, style) => MapEntry( token, diff --git a/demo/lib/styles.dart b/demo/lib/styles.dart index 57b2f6dfb..846f4f698 100644 --- a/demo/lib/styles.dart +++ b/demo/lib/styles.dart @@ -10,9 +10,9 @@ StyleMix get onSurfaceMix => StyleMix( ), ); -StyleMix get headingMix => StyleMix.fromAttributes([ +StyleMix get headingMix => StyleMix.create([ textStyle(fontSize: 24), - ...onSurfaceMix.toAttributes(), + ...onSurfaceMix.values, ]); StyleMix get flexAlign => StyleMix( diff --git a/demo/lib/theme.dart b/demo/lib/theme.dart index 0430b9523..42eefca08 100644 --- a/demo/lib/theme.dart +++ b/demo/lib/theme.dart @@ -39,7 +39,7 @@ MaterialStateProperty getPropertyForTrack(ThemeData theme) { if (states.contains(MaterialState.selected)) { return theme.colorScheme.secondary; } - + return null; }); } @@ -59,7 +59,7 @@ ThemeData get darkTheme { if (states.contains(MaterialState.hovered)) { return Colors.white; } - + return Colors.white.withAlpha(230); }), ), diff --git a/demo/lib/views/basic_example.dart b/demo/lib/views/basic_example.dart index 86cda3c67..fd1d891ea 100644 --- a/demo/lib/views/basic_example.dart +++ b/demo/lib/views/basic_example.dart @@ -9,16 +9,15 @@ class BasicExample extends HookWidget { @override Widget build(BuildContext context) { - final mix = StyleMix.fromAttributes([ + final mix = StyleMix.create([ height(300), width(300), rounded(10), animation(), elevation(2), margin(10), - alignment(Alignment.center), + alignmentCenter(), backgroundColor(Colors.purple), - alignment(Alignment.center), textStyle(color: Colors.white), onPress( backgroundColor(Colors.black), diff --git a/demo/lib/views/button_example.dart b/demo/lib/views/button_example.dart new file mode 100644 index 000000000..baec88cef --- /dev/null +++ b/demo/lib/views/button_example.dart @@ -0,0 +1,181 @@ +import 'package:flutter/widgets.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:mix/mix.dart'; + +enum SizeVariantEnum { + small, + medium, + large, +} + +enum LeadingPosition { left, center, right } + +@immutable +class ButtonSizeVariant extends Variant { + ButtonSizeVariant(T variant) : super(variant.name); +} + +class ButtonSizeVariants { + static final small = ButtonSizeVariant(SizeVariantEnum.small); + static final medium = ButtonSizeVariant(SizeVariantEnum.medium); + static final large = ButtonSizeVariant(SizeVariantEnum.large); +} + +StyleMix get _baseStyle => StyleMix( + rounded(4), + animation( + curve: Curves.easeIn, + duration: 100, + ), + onPress( + scale(0.95), + ), + mainAxisAlignment(MainAxisAlignment.center), + textStyle( + // added because of lack of style parameters (yellow lines) + decoration: TextDecoration.none, + fontWeight: FontWeight.w600, + fontFamily: MaterialTextStyles.bodySmall.fontFamily, + ), + mainAxisSize(MainAxisSize.min), // For flexbox + ButtonSizeVariants.small( + paddingHorizontal(10), + paddingVertical(10), + textStyle( + fontSize: 16, + ), + iconSize(24), + ), + ButtonSizeVariants.medium( + paddingHorizontal(4), + paddingVertical(16), + textStyle( + fontSize: 16, + ), + iconSize(24), + ), + ButtonSizeVariants.large( + paddingHorizontal(4), + paddingVertical(2), + textStyle( + fontSize: 16, + ), + iconSize(24), + ), + ); + +abstract class Button extends StatelessWidget { + const Button( + this.text, { + super.key, + this.size, + this.style, + this.onPressed, + this.onLongPressed, + this.leading, + this.leadingPosition = LeadingPosition.left, + this.interPadding = 12, // ultrashotTheme.spacing.w15 + }); + + final String text; + final ButtonSizeVariant? size; + final StyleMix? style; + final VoidCallback? onPressed; + final VoidCallback? onLongPressed; + final Widget? leading; + final LeadingPosition? leadingPosition; + final double? interPadding; + + Widget get _leftContent { + if (leading == null || + leading != null && leadingPosition != LeadingPosition.left) { + return SizedBox.fromSize(size: Size.zero); + } + + return Padding( + padding: EdgeInsets.only(right: interPadding!), + child: leading, + ); + } + + Widget get _centerContent { + if (leading != null && leadingPosition == LeadingPosition.center) { + return leading!; + } + + return StyledText( + text, + inherit: true, + style: StyleMix(), + ); + } + + Widget get _rightContent { + if (leading == null || + leading != null && leadingPosition != LeadingPosition.right) { + return SizedBox.fromSize(size: Size.zero); + } + + return Padding( + padding: EdgeInsets.only(left: interPadding!), + child: leading, + ); + } + + @override + Widget build(BuildContext context) { + final mergedStyle = _baseStyle + .selectVariant(size ?? ButtonSizeVariants.medium) + .merge(style); + + return Pressable( + onPressed: onPressed, + onLongPress: onLongPressed, + child: HBox( + style: mergedStyle, + children: [ + _leftContent, + _centerContent, + _rightContent, + ], + ), + ); + } +} + +StyleMix get _style => StyleMix( + textStyle( + color: const Color(0xFFFF004C), + ), + backgroundColor(const Color(0x0F07E2FF)), + iconColor(_MaterialDesignColors.onBackground), + onDisabled( + backgroundColor(_MaterialDesignColors.background.withOpacity(0.3)), + textStyle(color: _MaterialDesignColors.onBackground.withOpacity(0.3)), + iconColor(_MaterialDesignColors.onBackground.withOpacity(0.3)), + ), + ); + +class PrimaryButton extends Button { + PrimaryButton( + String text, { + super.key, + super.size, + super.onPressed, + super.onLongPressed, + super.leading, + super.leadingPosition, + }) : super(text, style: _style); +} + +class ButtonExample extends HookWidget { + const ButtonExample({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return PrimaryButton( + 'Primary Button', + onPressed: () => {}, + ); + } +} diff --git a/demo/lib/views/example.dart b/demo/lib/views/example.dart index b3aa251c9..ad86b78ba 100644 --- a/demo/lib/views/example.dart +++ b/demo/lib/views/example.dart @@ -67,7 +67,7 @@ class CustomMixWidget extends StatelessWidget { elevation(10), rounded(10), backgroundColor($M3Color.primary), - textStyle(as: $M3Text.bodyMedium), + textStyle(as: MaterialTextStyles.bodyMedium), textStyle(color: $M3Color.onPrimary), onHover( elevation(2), diff --git a/demo/lib/views/layout_example.dart b/demo/lib/views/layout_example.dart index eae16920c..ab9fc38c8 100644 --- a/demo/lib/views/layout_example.dart +++ b/demo/lib/views/layout_example.dart @@ -9,7 +9,7 @@ StyleMix get mix => StyleMix( rounded(10), elevation(2), backgroundColor($M3Color.surface), - alignment(Alignment.center), + alignmentCenter(), textStyle(color: $M3Color.onSurface), ); diff --git a/demo/lib/views/typography_example.dart b/demo/lib/views/typography_example.dart index 01c7f44d7..f1a9c9dff 100644 --- a/demo/lib/views/typography_example.dart +++ b/demo/lib/views/typography_example.dart @@ -6,7 +6,7 @@ import '../components/m3_typography.dart'; import '../styles.dart'; StyleMix get button => StyleMix( - textStyle(as: $M3Text.bodyMedium), + textStyle(as: MaterialTextStyles.bodyMedium), bold(), textStyle(fontSize: 6.0), backgroundColor($M3Color.primary), diff --git a/demo/lib/views/variants.dart b/demo/lib/views/variants.dart index fc5c9f882..c94bb1a5d 100644 --- a/demo/lib/views/variants.dart +++ b/demo/lib/views/variants.dart @@ -15,7 +15,7 @@ class VariantsExample extends HookWidget { rounded(10), elevation(2), margin(10), - alignment(Alignment.center), + alignmentCenter(), ); final style = StyleMix( diff --git a/demo/macos/Podfile.lock b/demo/macos/Podfile.lock index aeacdfbb8..689c202d5 100644 --- a/demo/macos/Podfile.lock +++ b/demo/macos/Podfile.lock @@ -22,7 +22,7 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: desktop_window: fb7c4f12c1129f947ac482296b6f14059d57a3c3 FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 - path_provider_foundation: c68054786f1b4f3343858c1e1d0caaded73f0be9 + path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943 PODFILE CHECKSUM: 353c8bcc5d5b0994e508d035b5431cfe18c1dea7 diff --git a/demo/macos/Runner.xcodeproj/project.pbxproj b/demo/macos/Runner.xcodeproj/project.pbxproj index 1621f70a6..eef3ddc64 100644 --- a/demo/macos/Runner.xcodeproj/project.pbxproj +++ b/demo/macos/Runner.xcodeproj/project.pbxproj @@ -203,7 +203,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 1300; + LastUpgradeCheck = 1430; ORGANIZATIONNAME = ""; TargetAttributes = { 33CC10EC2044A3C60003C045 = { diff --git a/demo/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/demo/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 6ee9022e4..15b420ad7 100644 --- a/demo/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/demo/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ =3.0.0 <4.0.0" - flutter: ">=3.3.0" + dart: ">=3.1.0-185.0.dev <4.0.0" + flutter: ">=3.7.0" diff --git a/deprecation.md b/deprecation.md index 45219f665..d85e33c77 100644 --- a/deprecation.md +++ b/deprecation.md @@ -15,6 +15,8 @@ There has been some considerable changes on the inter workings of Mix Context, t This does not impact the current behavior of Mix, but if you were building internal widgets or using the Builder most like this will be changed. +## Material Theme Tokens have been changed also + ## Inherit Mix has been removed Inheritance of Mix was turned on by default for Text and Icon widgets. However best practice now is to be explicit on which Mix to pass down, by passing the Mix itself. All inheritance has now been turn off to facilitate debugging and troubleshooting. Also we do plan better tooling for migration, and automation that makes a more explicit inheritance a much more favorable approach. diff --git a/lib/exports.dart b/lib/exports.dart new file mode 100644 index 000000000..60755ac2f --- /dev/null +++ b/lib/exports.dart @@ -0,0 +1,69 @@ +export 'mix.dart'; +export 'src/attributes/alignment_attribute.dart'; +export 'src/attributes/attribute.dart'; +export 'src/attributes/border/border_attribute.dart'; +export 'src/attributes/border/border_radius_attribute.dart'; +export 'src/attributes/color_attribute.dart'; +export 'src/attributes/constraints_attribute.dart'; +export 'src/attributes/decoration_attribute.dart'; +export 'src/attributes/edge_insets_attribute.dart'; +export 'src/attributes/scalar_attribute.dart'; +export 'src/attributes/shadow_attribute.dart'; +export 'src/attributes/space_attribute.dart'; +export 'src/attributes/strut_style_attribute.dart'; +export 'src/attributes/style_mix_attribute.dart'; +export 'src/attributes/text_style_attribute.dart'; +export 'src/attributes/variant_attribute.dart'; +export 'src/decorators/decorator.dart'; +export 'src/decorators/default_decorators.dart'; +export 'src/decorators/widget_decorator_wrapper.dart'; +export 'src/deprecations.dart'; +export 'src/directives/directive_attribute.dart'; +export 'src/directives/directives/controllers.dart'; +export 'src/directives/text_directive.dart'; +export 'src/factory/mix_provider.dart'; +export 'src/factory/mix_provider_data.dart'; +export 'src/factory/style_group.dart'; +export 'src/factory/style_mix.dart'; +export 'src/helpers/extensions/build_context_ext.dart'; +export 'src/helpers/extensions/iterable_ext.dart'; +export 'src/helpers/extensions/string_ext.dart'; +export 'src/helpers/extensions/style_mix_ext.dart'; +export 'src/helpers/extensions/values_ext.dart'; +export 'src/specs/container_spec.dart'; +export 'src/specs/flex_spec.dart'; +export 'src/specs/icon_spec.dart'; +export 'src/specs/image_spec.dart'; +export 'src/specs/stack_spec.dart'; +export 'src/specs/text_spec.dart'; +export 'src/theme/mix_theme.dart'; +export 'src/theme/tokens/breakpoints.dart'; +export 'src/theme/tokens/material_tokens.dart'; +export 'src/theme/tokens/mix_token.dart'; +export 'src/theme/tokens/space_token.dart'; +export 'src/theme/tokens/text_style_token.dart'; +export 'src/utils/alignment_util.dart'; +export 'src/utils/border_radius_util.dart'; +export 'src/utils/border_util.dart'; +export 'src/utils/box_constraints_util.dart'; +export 'src/utils/context_variant_util.dart'; +export 'src/utils/decoration_util.dart'; +export 'src/utils/gradient_util.dart'; +export 'src/utils/helper_util.dart'; +export 'src/utils/pressable_util.dart'; +export 'src/utils/scalar_util.dart'; +export 'src/utils/space_util.dart'; +export 'src/utils/text_directives_util.dart'; +export 'src/utils/text_util.dart'; +export 'src/variants/context_variant.dart'; +export 'src/variants/variant.dart'; +export 'src/widgets/container_widget.dart'; +export 'src/widgets/empty_widget.dart'; +export 'src/widgets/flex_widget.dart'; +export 'src/widgets/icon_widget.dart'; +export 'src/widgets/pressable/pressable.notifier.dart'; +export 'src/widgets/pressable/pressable_state.dart'; +export 'src/widgets/pressable/pressable_widget.dart'; +export 'src/widgets/stack_widget.dart'; +export 'src/widgets/styled_widget.dart'; +export 'src/widgets/text_widget.dart'; diff --git a/lib/mix.dart b/lib/mix.dart index b5de084b2..f2eea19d9 100644 --- a/lib/mix.dart +++ b/lib/mix.dart @@ -1,11 +1,4 @@ library mix; -export 'src/aliases/exports.dart'; -export 'src/attributes/exports.dart'; -export 'src/decorators/exports.dart'; -export 'src/extensions/exports.dart'; -export 'src/factory/exports.dart'; -export 'src/helpers/exports.dart'; -export 'src/theme/exports.dart'; -export 'src/variants/exports.dart'; -export 'src/widgets/exports.dart'; +export './exports.dart'; +export 'src/deprecations.dart'; diff --git a/lib/src/aliases/common_alias.dart b/lib/src/aliases/common_alias.dart deleted file mode 100644 index 3b1b52b4c..000000000 --- a/lib/src/aliases/common_alias.dart +++ /dev/null @@ -1,9 +0,0 @@ -import '../attributes/shared/shared.utilities.dart'; - -const show = CommonUtility.visible; -const hide = CommonUtility.hidden; - -const animation = CommonUtility.animation; -const animationDuration = CommonUtility.animationDuration; -const animationCurve = CommonUtility.animationCurve; -const textDirection = CommonUtility.textDirection; diff --git a/lib/src/aliases/container_alias.dart b/lib/src/aliases/container_alias.dart deleted file mode 100644 index 820108671..000000000 --- a/lib/src/aliases/container_alias.dart +++ /dev/null @@ -1,291 +0,0 @@ -import '../../mix.dart'; - -final margin = WrapWithSpaceTokens(ContainerStyleUtilities().margin); -final marginTop = WrapWithSpaceTokens(ContainerStyleUtilities().marginTop); -final marginBottom = - WrapWithSpaceTokens(ContainerStyleUtilities().marginBottom); -final marginRight = WrapWithSpaceTokens(ContainerStyleUtilities().marginRight); -final marginLeft = WrapWithSpaceTokens(ContainerStyleUtilities().marginLeft); -final marginDirectionalStart = WrapWithSpaceTokens( - ContainerStyleUtilities().marginDirectionalStart, -); - -final marginDirectionalEnd = WrapWithSpaceTokens( - ContainerStyleUtilities().marginDirectionalEnd, -); - -final marginSymmetric = ContainerStyleUtilities().marginSymmetric; -final marginHorizontal = ContainerStyleUtilities().marginHorizontal; -final marginVertical = ContainerStyleUtilities().marginVertical; - -final marginInsets = ContainerStyleUtilities().marginInsets; - -final padding = WrapWithSpaceTokens(ContainerStyleUtilities().padding); -final paddingTop = WrapWithSpaceTokens(ContainerStyleUtilities().paddingTop); -final paddingBottom = - WrapWithSpaceTokens(ContainerStyleUtilities().paddingBottom); -final paddingRight = - WrapWithSpaceTokens(ContainerStyleUtilities().paddingRight); -final paddingLeft = WrapWithSpaceTokens(ContainerStyleUtilities().paddingLeft); - -final paddingSymmetric = ContainerStyleUtilities().paddingSymmetric; -final paddingHorizontal = ContainerStyleUtilities().paddingHorizontal; -final paddingVertical = ContainerStyleUtilities().paddingVertical; -final paddingInsets = ContainerStyleUtilities().paddingInsets; - -final paddingDirectionalStart = WrapWithSpaceTokens( - ContainerStyleUtilities().paddingDirectionalStart, -); -final paddingDirectionalEnd = WrapWithSpaceTokens( - ContainerStyleUtilities().paddingDirectionalEnd, -); - -final paddingDirectionalTop = WrapWithSpaceTokens( - ContainerStyleUtilities().paddingDirectionalTop, -); - -final paddingDirectionalBottom = WrapWithSpaceTokens( - ContainerStyleUtilities().paddingDirectionalBottom, -); - -// Transform -final transform = ContainerStyleUtilities().transform; - -/// Background color attribute -final backgroundColor = ContainerStyleUtilities().backgroundColor; - -/// Height -final height = ContainerStyleUtilities().height; - -/// Width -final width = ContainerStyleUtilities().width; - -/// Max height attribute -final maxHeight = ContainerStyleUtilities().maxHeight; - -/// Max width attribute -final maxWidth = ContainerStyleUtilities().maxWidth; - -/// Min height attribute -final minHeight = ContainerStyleUtilities().minHeight; - -/// Min width attribute -final minWidth = ContainerStyleUtilities().minWidth; - -/// Border -final border = ContainerStyleUtilities().border; -final borderTop = ContainerStyleUtilities().borderTop; -final borderBottom = ContainerStyleUtilities().borderBottom; -final borderLeft = ContainerStyleUtilities().borderLeft; -final borderRight = ContainerStyleUtilities().borderRight; - -// Border Directional - -final borderDirectionalTop = ContainerStyleUtilities().borderDirectionalTop; -final borderDirectionalBottom = - ContainerStyleUtilities().borderDirectionalBottom; -final borderDirectionalStart = ContainerStyleUtilities().borderDirectionalStart; -final borderDirectionalEnd = ContainerStyleUtilities().borderDirectionalEnd; - -/// Box shadow utility -final shadow = ContainerStyleUtilities().shadow; - -final squared = ContainerStyleUtilities().squared; - -final rounded = ContainerStyleUtilities().rounded; -final roundedOnly = ContainerStyleUtilities().roundedOnly; -final roundedHorizontal = ContainerStyleUtilities().roundedHorizontal; -final roundedVertical = ContainerStyleUtilities().roundedVertical; -final roundedDirectionalHorizontal = - ContainerStyleUtilities().roundedDirectionalHorizontal; -final roundedDirectionalVertical = - ContainerStyleUtilities().roundedDirectionalVertical; - -final alignment = ContainerStyleUtilities().alignment; - -/// Elevation -final elevation = ContainerStyleUtilities().elevation; - -/// Gradient -final linearGradient = ContainerStyleUtilities().linearGradient; -final radialGradient = ContainerStyleUtilities().radialGradient; - -const kShortAliasDeprecation = - 'Short aliases will be deprecated, you can create your own. Example: final p = padding;'; - -@Deprecated(kShortAliasDeprecation) -final p = padding; - -@Deprecated(kShortAliasDeprecation) -final pt = paddingTop; - -@Deprecated(kShortAliasDeprecation) -final pb = paddingBottom; - -@Deprecated(kShortAliasDeprecation) -final pr = paddingRight; - -@Deprecated(kShortAliasDeprecation) -final pl = paddingLeft; - -@Deprecated(kShortAliasDeprecation) -final ps = paddingStart; - -@Deprecated(kShortAliasDeprecation) -final pe = paddingEnd; - -@Deprecated(kShortAliasDeprecation) -final px = paddingHorizontal; - -@Deprecated(kShortAliasDeprecation) -final py = paddingVertical; - -@Deprecated(kShortAliasDeprecation) -final pi = ContainerStyleUtilities().paddingInsets; - -@Deprecated(kShortAliasDeprecation) -final m = WrapWithSpaceTokens(ContainerStyleUtilities().margin); -@Deprecated(kShortAliasDeprecation) -final mt = WrapWithSpaceTokens(ContainerStyleUtilities().marginTop); -@Deprecated(kShortAliasDeprecation) -final mb = WrapWithSpaceTokens(ContainerStyleUtilities().marginBottom); -@Deprecated(kShortAliasDeprecation) -final mr = WrapWithSpaceTokens(ContainerStyleUtilities().marginRight); -@Deprecated(kShortAliasDeprecation) -final ml = WrapWithSpaceTokens(ContainerStyleUtilities().marginLeft); -@Deprecated(kShortAliasDeprecation) -final ms = WrapWithSpaceTokens(ContainerStyleUtilities().marginStart); -@Deprecated(kShortAliasDeprecation) -final me = WrapWithSpaceTokens(ContainerStyleUtilities().marginEnd); -@Deprecated(kShortAliasDeprecation) -final mx = WrapWithSpaceTokens(ContainerStyleUtilities().marginHorizontal); -@Deprecated(kShortAliasDeprecation) -final my = WrapWithSpaceTokens(ContainerStyleUtilities().marginVertical); -@Deprecated(kShortAliasDeprecation) -final mi = ContainerStyleUtilities().marginInsets; - -@Deprecated(kShortAliasDeprecation) -final marginX = marginHorizontal; - -@Deprecated(kShortAliasDeprecation) -final marginY = marginVertical; - -@Deprecated(kShortAliasDeprecation) -final r = ContainerStyleUtilities().rounded; - -@Deprecated(kShortAliasDeprecation) -final roundedH = ContainerStyleUtilities().roundedHorizontal; - -@Deprecated(kShortAliasDeprecation) -final roundedV = ContainerStyleUtilities().roundedVertical; - -@Deprecated(kShortAliasDeprecation) -final roundedDH = ContainerStyleUtilities().roundedDirectionalHorizontal; - -@Deprecated(kShortAliasDeprecation) -StyledContainerAttributes roundedTL(double value) { - return ContainerStyleUtilities().roundedOnly(topLeft: value); -} - -@Deprecated(kShortAliasDeprecation) -StyledContainerAttributes roundedTR(double value) { - return ContainerStyleUtilities().roundedOnly(topRight: value); -} - -@Deprecated(kShortAliasDeprecation) -StyledContainerAttributes roundedBL(double value) { - return ContainerStyleUtilities().roundedOnly(bottomLeft: value); -} - -@Deprecated(kShortAliasDeprecation) -StyledContainerAttributes roundedBR(double value) { - return ContainerStyleUtilities().roundedOnly(bottomRight: value); -} - -@Deprecated(kShortAliasDeprecation) -StyledContainerAttributes roundedTS(double value) { - return ContainerStyleUtilities().roundedDirectionalOnly(topStart: value); -} - -@Deprecated(kShortAliasDeprecation) -StyledContainerAttributes roundedTE(double value) { - return ContainerStyleUtilities().roundedDirectionalOnly(topEnd: value); -} - -@Deprecated(kShortAliasDeprecation) -StyledContainerAttributes roundedBS(double value) { - return ContainerStyleUtilities().roundedDirectionalOnly(bottomStart: value); -} - -@Deprecated(kShortAliasDeprecation) -StyledContainerAttributes roundedBE(double value) { - return ContainerStyleUtilities().roundedDirectionalOnly(bottomEnd: value); -} - -@Deprecated(kShortAliasDeprecation) -final bgColor = ContainerStyleUtilities().backgroundColor; - -@Deprecated(kShortAliasDeprecation) -final h = ContainerStyleUtilities().height; - -@Deprecated(kShortAliasDeprecation) -final w = ContainerStyleUtilities().width; - -@Deprecated(kShortAliasDeprecation) -final maxH = ContainerStyleUtilities().maxHeight; - -@Deprecated(kShortAliasDeprecation) -final maxW = ContainerStyleUtilities().maxWidth; - -@Deprecated(kShortAliasDeprecation) -final minH = ContainerStyleUtilities().minHeight; - -@Deprecated(kShortAliasDeprecation) -final minW = ContainerStyleUtilities().minWidth; - -@Deprecated(kShortAliasDeprecation) -final bt = ContainerStyleUtilities().borderTop; - -@Deprecated(kShortAliasDeprecation) -final bb = ContainerStyleUtilities().borderBottom; - -@Deprecated(kShortAliasDeprecation) -final bl = ContainerStyleUtilities().borderLeft; - -@Deprecated(kShortAliasDeprecation) -final br = ContainerStyleUtilities().borderRight; - -@Deprecated(kShortAliasDeprecation) -final bs = ContainerStyleUtilities().borderStart; - -@Deprecated(kShortAliasDeprecation) -final be = ContainerStyleUtilities().borderEnd; - -@Deprecated('Use paddingDirectionalStart instead') -final paddingStart = - WrapWithSpaceTokens(ContainerStyleUtilities().paddingStart); -@Deprecated('Use paddingDirectionalEnd instead') -final paddingEnd = WrapWithSpaceTokens(ContainerStyleUtilities().paddingEnd); - -@Deprecated('Use borderDirectionalStart instead') -final borderStart = ContainerStyleUtilities().borderStart; - -@Deprecated('Use borderDirectionalEnd instead') -final borderEnd = ContainerStyleUtilities().borderEnd; - -@Deprecated('Use border(color:color) instead') -final borderColor = ContainerStyleUtilities().borderColor; - -@Deprecated('Use border(width:width) instead') -final borderWidth = ContainerStyleUtilities().borderWidth; - -@Deprecated('Use border(color:color) instead') -final borderStyle = ContainerStyleUtilities().borderStyle; - -@Deprecated('Use alignment instead') -final align = alignment; - -@Deprecated('Use marginDirectionalStart instead') -final marginStart = WrapWithSpaceTokens(ContainerStyleUtilities().marginStart); -@Deprecated('Use marginDirectionalEnd instead') -final marginEnd = WrapWithSpaceTokens(ContainerStyleUtilities().marginEnd); diff --git a/lib/src/aliases/context_variants_alias.dart b/lib/src/aliases/context_variants_alias.dart deleted file mode 100644 index 9bbde4343..000000000 --- a/lib/src/aliases/context_variants_alias.dart +++ /dev/null @@ -1,21 +0,0 @@ -// Dynamic utilities -import '../variants/utilities/context_variant_utilities.dart'; - -final onXSmall = ContextVariantUtilities.onXsmall(); -final onMedium = ContextVariantUtilities.onMedium(); -final onSmall = ContextVariantUtilities.onSmall(); -final onLarge = ContextVariantUtilities.onLarge(); -final onPortrait = ContextVariantUtilities.onPortrait(); -final onLandscape = ContextVariantUtilities.onLandscape(); -final onDark = ContextVariantUtilities.onDark(); -final onLight = ContextVariantUtilities.onLight(); -final onRTL = ContextVariantUtilities.onRTL(); -final onLTR = onNot(onRTL); - -final onDisabled = ContextVariantUtilities.onDisabled(); -final onFocus = ContextVariantUtilities.onFocus(); -final onHover = ContextVariantUtilities.onHover(); -final onPress = ContextVariantUtilities.onPress(); -final onLongPress = ContextVariantUtilities.onLongPress(); -const onNot = ContextVariantUtilities.onNot; -final onEnabled = onNot(onDisabled); diff --git a/lib/src/aliases/decorator_alias.dart b/lib/src/aliases/decorator_alias.dart deleted file mode 100644 index bb3dd4d59..000000000 --- a/lib/src/aliases/decorator_alias.dart +++ /dev/null @@ -1,21 +0,0 @@ -import '../decorators/decorators_utilities.dart'; - -const aspectRatio = DecoratorUtility.aspectRatio; - -const scale = DecoratorUtility.scale; - -const opacity = DecoratorUtility.opacity; - -const flex = DecoratorUtility.flex; -const flexFit = DecoratorUtility.flexFit; -const expanded = DecoratorUtility.expanded; -const flexible = DecoratorUtility.flexible; - -const clipRounded = DecoratorUtility.clipRounded; -const clipOval = DecoratorUtility.clipOval; -const clipTriangle = DecoratorUtility.clipTriangle; - -const rotate = DecoratorUtility.rotate; -const rotate90 = DecoratorUtility.rotate90; -const rotate180 = DecoratorUtility.rotate180; -const rotate270 = DecoratorUtility.rotate270; diff --git a/lib/src/aliases/deprecated_alias.dart b/lib/src/aliases/deprecated_alias.dart deleted file mode 100644 index b99054b2a..000000000 --- a/lib/src/aliases/deprecated_alias.dart +++ /dev/null @@ -1,124 +0,0 @@ -import '../../mix.dart'; -import '../widgets/text/text_legacy.utilities.dart'; - -/// ALL ALIASES HERE HAVE BEEN DEPRECATED AND WILL BE REMOVED IN THE FUTURE -/// FEEL FREE TO BRING INTERNALLY TO YOUR OWN PROJECT -@Deprecated('Use animation instead') -const animated = CommonUtility.animation; - -@Deprecated('Use mainAxisAlignment instead') -final mainAxis = mainAxisAlignment; - -@Deprecated('use Mix.chooser instead') -void when(bool _) => throw UnimplementedError(); - -@Deprecated('Use onXSmall instead') -final xsmall = onXSmall; - -@Deprecated('Use onSmall instead') -final small = onSmall; - -@Deprecated('Use onMedium instead') -final medium = onMedium; - -@Deprecated('Use onDark instead') -final dark = onDark; - -@Deprecated('Use onLight instead') -final light = onLight; - -@Deprecated('Use onLarge instead') -final large = onLarge; - -@Deprecated('Use onHover instead') -final hover = onHover; - -@Deprecated('Use onFocus instead') -final focus = onFocus; - -@Deprecated('Use onPortrait instead') -final portrait = onPortrait; - -@Deprecated('Use onLandscape instead') -final landscape = onLandscape; - -@Deprecated('Use onDisabled instead') -final disabled = onDisabled; - -@Deprecated('Use onEnabled instead') -final enabled = onEnabled; - -@Deprecated('Use onPress instead') -final press = onPress; - -@Deprecated('Use onNot instead') -const not = onNot; - -@Deprecated('Use textStyle instead') -const font = textStyle; - -@Deprecated('Use textStyle(textShadow: textShadow) instead') -const textShadow = LegacyTextFriendlyUtility.textShadow; - -@Deprecated('Use textStyle(textShadow: textShadow) instead') -const fontWeight = LegacyTextStyleUtility.fontWeight; - -@Deprecated('Use textStyle(textBaseline: textBaseline) instead') -const textBaseline = LegacyTextStyleUtility.textBaseline; - -@Deprecated('Use textStyle(letterSpacing: letterSpacing) instead') -const letterSpacing = LegacyTextStyleUtility.letterSpacing; - -@Deprecated('Use textStyle(debugLabel: debugLabel) instead') -const debugLabel = LegacyTextStyleUtility.debugLabel; - -@Deprecated('Use textStyle(height: height) instead') -const textHeight = LegacyTextStyleUtility.height; - -@Deprecated('Use textStyle(wordSpacing: wordSpacing) instead') -const wordSpacing = LegacyTextStyleUtility.wordSpacing; - -@Deprecated('Use textStyle(fontStyle: fontStyle) instead') -const fontStyle = LegacyTextStyleUtility.fontStyle; - -@Deprecated('Use textStyle(fontSize: fontSize) instead') -const fontSize = LegacyTextStyleUtility.fontSize; - -@Deprecated('Use textStyle(inherit: inherit) instead') -const inherit = LegacyTextStyleUtility.inherit; - -@Deprecated('Use textStyle(color: color) instead') -const textColor = LegacyTextStyleUtility.color; - -@Deprecated('Use textStyle(backgroundColor: backgroundColor) instead') -const textBgColor = LegacyTextStyleUtility.backgroundColor; - -@Deprecated('Use textStyle(foreground: foreground) instead') -const textForeground = LegacyTextStyleUtility.foreground; - -@Deprecated('Use textStyle(background: background) instead') -const textBackground = LegacyTextStyleUtility.background; - -@Deprecated('Use textStyle(shadows: shadows) instead') -const textShadows = LegacyTextStyleUtility.shadows; - -@Deprecated('Use textStyle(fontFeatures: fontFeatures) instead') -const fontFeatures = LegacyTextStyleUtility.fontFeatures; - -@Deprecated('Use textStyle(decoration: decoration) instead') -const textDecoration = LegacyTextStyleUtility.decoration; - -@Deprecated('Use textStyle(decorationColor: decorationColor) instead') -const textDecorationColor = LegacyTextStyleUtility.decorationColor; - -@Deprecated('Use textStyle(decorationStyle: decorationStyle) instead') -const textDecorationStyle = LegacyTextStyleUtility.decorationStyle; - -@Deprecated('Use textStyle(decorationThickness: decorationThickness) instead') -const textDecorationThickness = LegacyTextStyleUtility.decorationThickness; - -@Deprecated('Use textStyle(fontFamilyFallback: fontFamilyFallback) instead') -const fontFamilyFallback = LegacyTextStyleUtility.fontFamilyFallback; - -@Deprecated('Use style.merge(otherStyle), instead') -const apply = SpreadPositionalParams(HelperUtility.apply); diff --git a/lib/src/aliases/exports.dart b/lib/src/aliases/exports.dart deleted file mode 100644 index 4740c3bd6..000000000 --- a/lib/src/aliases/exports.dart +++ /dev/null @@ -1,11 +0,0 @@ -export 'common_alias.dart'; -export 'container_alias.dart'; -export 'context_variants_alias.dart'; -export 'decorator_alias.dart'; -export 'deprecated_alias.dart'; -export 'flex_alias.dart'; -export 'icon_alias.dart'; -export 'image_alias.dart'; -export 'stack_alias.dart'; -export 'text_alias.dart'; -export 'token_alias.dart'; diff --git a/lib/src/aliases/flex_alias.dart b/lib/src/aliases/flex_alias.dart deleted file mode 100644 index 55ca0ec5c..000000000 --- a/lib/src/aliases/flex_alias.dart +++ /dev/null @@ -1,8 +0,0 @@ -import '../widgets/flex/flex.utilities.dart'; - -final flexDirection = const FlexUtilities().direction; -final verticalDirection = const FlexUtilities().verticalDirection; -final mainAxisAlignment = const FlexUtilities().mainAxisAlignment; -final mainAxisSize = const FlexUtilities().mainAxisSize; -final crossAxis = const FlexUtilities().crossAxisAlignment; -final gap = const FlexUtilities().gap; diff --git a/lib/src/aliases/icon_alias.dart b/lib/src/aliases/icon_alias.dart deleted file mode 100644 index b1a05bbaa..000000000 --- a/lib/src/aliases/icon_alias.dart +++ /dev/null @@ -1,5 +0,0 @@ -import '../widgets/icon/icon.utilities.dart'; - -const icon = IconUtility.icon; -const iconSize = IconUtility.iconSize; -const iconColor = IconUtility.iconColor; diff --git a/lib/src/aliases/image_alias.dart b/lib/src/aliases/image_alias.dart deleted file mode 100644 index ee1ace3c4..000000000 --- a/lib/src/aliases/image_alias.dart +++ /dev/null @@ -1,10 +0,0 @@ -import '../widgets/image/image.utilities.dart'; - -const image = ImageUtility.image; - -const imageColor = ImageUtility.color; -const imageScale = ImageUtility.scale; -const imageColorBlendMode = ImageUtility.colorBlendMode; -const imageFit = ImageUtility.fit; -const imageAlignment = ImageUtility.alignment; -const imageRepeat = ImageUtility.repeat; diff --git a/lib/src/aliases/stack_alias.dart b/lib/src/aliases/stack_alias.dart deleted file mode 100644 index 5f4dc9649..000000000 --- a/lib/src/aliases/stack_alias.dart +++ /dev/null @@ -1,5 +0,0 @@ -import '../widgets/stack/stack.utilities.dart'; - -const zAligmnent = ZBoxUtility.alignment; -const zFit = ZBoxUtility.fit; -const zClip = ZBoxUtility.clipBehavior; diff --git a/lib/src/aliases/text_alias.dart b/lib/src/aliases/text_alias.dart deleted file mode 100644 index 251b2854f..000000000 --- a/lib/src/aliases/text_alias.dart +++ /dev/null @@ -1,27 +0,0 @@ -import '../widgets/text/text.utilities.dart'; -import '../widgets/text/text_directives/text_directives.dart'; - -/// Text align -const textAlign = TextUtility.textAlign; - -const textWidthBasis = TextUtility.textWidthBasis; -const locale = TextUtility.locale; -const maxLines = TextUtility.maxLines; -const textOverflow = TextUtility.overflow; -const textStyle = TextUtility.textStyle; -const softWrap = TextUtility.softWrap; -const textScaleFactor = TextUtility.textScaleFactor; -const strutStyle = TextUtility.strutStyle; - -/// Friendly utilities - -const bold = TextFriendlyUtility.bold; -const italic = TextFriendlyUtility.italic; - -/// Directives - -final capitalize = TextUtility.directive(const CapitalizeDirective()); -final upperCase = TextUtility.directive(const UppercaseDirective()); -final lowerCase = TextUtility.directive(const LowercaseDirective()); -final titleCase = TextUtility.directive(const TitleCaseDirective()); -final sentenceCase = TextUtility.directive(const SentenceCaseDirective()); diff --git a/lib/src/aliases/token_alias.dart b/lib/src/aliases/token_alias.dart deleted file mode 100644 index 9fb4d7b3b..000000000 --- a/lib/src/aliases/token_alias.dart +++ /dev/null @@ -1,19 +0,0 @@ -// Allow to use space tokens references within mix -import '../../mix.dart'; - -final $space = _SpaceTokensRef(); - -class _SpaceTokensRef { - _SpaceTokensRef._(); - - static final _SpaceTokensRef instance = _SpaceTokensRef._(); - - factory _SpaceTokensRef() => instance; - - final xsmall = SpaceTokens.xsmall.ref; - final small = SpaceTokens.small.ref; - final medium = SpaceTokens.medium.ref; - final large = SpaceTokens.large.ref; - final xlarge = SpaceTokens.xlarge.ref; - final xxlarge = SpaceTokens.xxlarge.ref; -} diff --git a/lib/src/attributes/alignment_attribute.dart b/lib/src/attributes/alignment_attribute.dart new file mode 100644 index 000000000..363442330 --- /dev/null +++ b/lib/src/attributes/alignment_attribute.dart @@ -0,0 +1,123 @@ +import 'package:flutter/material.dart'; + +import '../factory/mix_provider_data.dart'; +import 'attribute.dart'; + +@immutable +abstract class AlignmentGeometryAttribute + extends VisualAttribute { + final double? start; + final double? x; + final double? y; + + const AlignmentGeometryAttribute({this.start, this.x, this.y}); + + @override + AlignmentGeometryAttribute merge( + covariant AlignmentGeometryAttribute? other, + ); + + @override + T resolve(MixData mix); + + @override + get props => [start, x, y]; +} + +@immutable +class AlignmentAttribute extends AlignmentGeometryAttribute { + /// The top left corner. + static const topLeft = AlignmentAttribute.pos(-1.0, -1.0); + + /// The center point along the top edge. + static const topCenter = AlignmentAttribute.pos(0.0, -1.0); + + /// The top right corner. + static const topRight = AlignmentAttribute.pos(1.0, -1.0); + + /// The center point along the left edge. + static const centerLeft = AlignmentAttribute.pos(-1.0, 0.0); + + /// The center point, both horizontally and vertically. + static const center = AlignmentAttribute.pos(0.0, 0.0); + + /// The center point along the right edge. + static const centerRight = AlignmentAttribute.pos(1.0, 0.0); + + /// The bottom left corner. + static const bottomLeft = AlignmentAttribute.pos(-1.0, 1.0); + + /// The center point along the bottom edge. + static const bottomCenter = AlignmentAttribute.pos(0.0, 1.0); + + /// The bottom right corner. + static const bottomRight = AlignmentAttribute.pos(1.0, 1.0); + + const AlignmentAttribute({super.x, super.y}); + + const AlignmentAttribute.pos(double x, double y) : this(x: x, y: y); + + @override + AlignmentAttribute merge(AlignmentAttribute? other) { + return AlignmentAttribute(x: other?.x ?? x, y: other?.y ?? y); + } + + @override + Alignment resolve(MixData mix) => Alignment(x ?? 0, y ?? 0); +} + +@immutable +class AlignmentDirectionalAttribute + extends AlignmentGeometryAttribute { + /// The top corner on the "start" side. + static const topStart = AlignmentDirectionalAttribute.pos(-1.0, -1.0); + + /// The center point along the top edge. + /// + /// Consider using [Alignment.topCenter] instead, as it does not need + /// to be [resolve]d to be used. + static const topCenter = AlignmentDirectionalAttribute.pos(0.0, -1.0); + + /// The top corner on the "end" side. + static const topEnd = AlignmentDirectionalAttribute.pos(1.0, -1.0); + + /// The center point along the "start" edge. + static const centerStart = AlignmentDirectionalAttribute.pos(-1.0, 0.0); + + /// The center point, both horizontally and vertically. + /// + /// Consider using [Alignment.center] instead, as it does not need to + /// be [resolve]d to be used. + static const center = AlignmentDirectionalAttribute.pos(0.0, 0.0); + + /// The center point along the "end" edge. + static const centerEnd = AlignmentDirectionalAttribute.pos(1.0, 0.0); + + /// The bottom corner on the "start" side. + static const bottomStart = AlignmentDirectionalAttribute.pos(-1.0, 1.0); + + /// The center point along the bottom edge. + /// + /// Consider using [Alignment.bottomCenter] instead, as it does not + /// need to be [resolve]d to be used. + static const bottomCenter = AlignmentDirectionalAttribute.pos(0.0, 1.0); + + /// The bottom corner on the "end" side. + static const bottomEnd = AlignmentDirectionalAttribute.pos(1.0, 1.0); + + const AlignmentDirectionalAttribute({super.start, super.y}); + + const AlignmentDirectionalAttribute.pos(double start, double y) + : this(start: start, y: y); + @override + AlignmentDirectionalAttribute merge(AlignmentDirectionalAttribute? other) { + return AlignmentDirectionalAttribute( + start: other?.start ?? start, + y: other?.y ?? y, + ); + } + + @override + AlignmentDirectional resolve(MixData mix) => + AlignmentDirectional(start ?? 0, y ?? 0); +} diff --git a/lib/src/attributes/attribute.dart b/lib/src/attributes/attribute.dart index cac8c38e7..2a8d2dcf1 100644 --- a/lib/src/attributes/attribute.dart +++ b/lib/src/attributes/attribute.dart @@ -1,22 +1,109 @@ -import '../helpers/equality_mixin/equality_mixin.dart'; +import 'dart:math'; -/// Base attribute +import 'package:flutter/material.dart'; -// Some classes have defaults -// Facade allows us ot set all properties as optional -// For improved merge and override of properties -abstract class StyleAttribute with EqualityMixin { - const StyleAttribute(); +import '../core/equality/compare_mixin.dart'; +import '../factory/mix_provider_data.dart'; + +@immutable +abstract class Attribute with Comparable, Mergeable { + const Attribute(); +} + +mixin Resolvable { + T resolve(MixData mix); } mixin Mergeable { T merge(covariant T? other); + + List mergeMergeableList( + List? current, + List? other, + ) { + if (current == null && other == null) return []; + if (current == null) return other ?? []; + if (other == null) return current; + + if (current.isEmpty) return other; + + final listLength = current.length; + final otherLength = other.length; + final maxLength = max(listLength, otherLength); + + return List.generate(maxLength, (int index) { + if (index < listLength && index < otherLength) { + final currentValue = current[index]; + final otherValue = other[index]; + + return currentValue.merge(otherValue); + } else if (index < listLength) { + return current[index]; + } + + return other[index]; + }); + } +} + +@immutable +abstract class ScalarAttribute, R> + extends VisualAttribute { + final R value; + + const ScalarAttribute(this.value); + + // Factory for merge methods + // ignore: avoid-shadowing + T create(R value); + + @override + R resolve(MixData mix) { + return value is Resolvable ? (value as Resolvable).resolve(mix) : value; + } + + @override + T merge(T? other) { + if (other == null) return create(value); + + return value is Mergeable + ? create((value as Mergeable).merge(other.value)) + : create(other.value); + } + + @override + get props => [value]; +} + +@immutable +abstract class VisualAttribute extends Attribute with Resolvable { + const VisualAttribute(); } -/// An interface that add support to custom attributes for [MixContext]. -abstract class StyledWidgetAttributes extends StyleAttribute - with Mergeable { - const StyledWidgetAttributes(); +@immutable +abstract class MixExtension> extends ThemeExtension + with Comparable { + const MixExtension(); + + Duration lerpDuration(Duration a, Duration b, double t) { + int lerpTicks = ((1 - t) * a.inMilliseconds + t * b.inMilliseconds).round(); + + return Duration(milliseconds: lerpTicks); + } + + int lerpInt(int a, int b, double t) { + return ((1 - t) * a + t * b).round(); + } + + N? genericNumLerp(N? a, N? b, double t) { + if (a == null && b == null) return null; + if (a == null) return b; + if (b == null) return a; + + return (a * (1 - t) + b * t) as N; + } - StyledWidgetAttributes copyWith(); + P snap

(P from, P to, double t) { + return t < 0.5 ? from : to; + } } diff --git a/lib/src/attributes/border/border_attribute.dart b/lib/src/attributes/border/border_attribute.dart new file mode 100644 index 000000000..90a4ea18a --- /dev/null +++ b/lib/src/attributes/border/border_attribute.dart @@ -0,0 +1,189 @@ +import 'package:flutter/material.dart'; + +import '../../factory/mix_provider_data.dart'; +import '../attribute.dart'; +import '../color_attribute.dart'; + +@immutable +abstract class BoxBorderAttribute + extends VisualAttribute { + final BorderSideAttribute? top; + + final BorderSideAttribute? bottom; + + const BoxBorderAttribute({this.top, this.bottom}); + + @override + BoxBorderAttribute merge(covariant BoxBorderAttribute? other); + + @override + T resolve(MixData mix); + + @override + get props => [top, bottom]; +} + +class BorderAttribute extends BoxBorderAttribute { + final BorderSideAttribute? left; + final BorderSideAttribute? right; + + const BorderAttribute({this.left, this.right, super.top, super.bottom}); + + const BorderAttribute.all(BorderSideAttribute side) + : this(left: side, right: side, top: side, bottom: side); + + const BorderAttribute.symmetric({ + BorderSideAttribute? vertical, + BorderSideAttribute? horizontal, + }) : this( + left: vertical, + right: vertical, + top: horizontal, + bottom: horizontal, + ); + + @override + BorderAttribute merge(BoxBorderAttribute? other) { + if (other == null) return this; + final otherAttribute = other as BorderAttribute; // cast the other instance + + return BorderAttribute( + left: left?.merge(otherAttribute.left) ?? otherAttribute.left, + right: right?.merge(otherAttribute.right) ?? otherAttribute.right, + top: top?.merge(other.top) ?? other.top, + bottom: bottom?.merge(other.bottom) ?? other.bottom, + ); + } + + @override + Border resolve(MixData mix) { + return Border( + top: top?.resolve(mix) ?? BorderSide.none, + right: right?.resolve(mix) ?? BorderSide.none, + bottom: bottom?.resolve(mix) ?? BorderSide.none, + left: left?.resolve(mix) ?? BorderSide.none, + ); + } + + @override + List get props => [top, bottom, left, right]; +} + +class BorderDirectionalAttribute extends BoxBorderAttribute { + final BorderSideAttribute? start; + final BorderSideAttribute? end; + + const BorderDirectionalAttribute({ + this.start, + this.end, + super.top, + super.bottom, + }); + + const BorderDirectionalAttribute.all(BorderSideAttribute side) + : this(start: side, end: side, top: side, bottom: side); + + const BorderDirectionalAttribute.symmetric({ + BorderSideAttribute? vertical, + BorderSideAttribute? horizontal, + }) : this( + start: horizontal, + end: horizontal, + top: vertical, + bottom: vertical, + ); + + BorderAttribute toBorder() { + return BorderAttribute( + left: start, + right: end, + top: top, + bottom: bottom, + ); + } + + @override + BorderDirectionalAttribute merge( + BoxBorderAttribute? other, + ) { + if (other == null) return this; + final otherAttribute = + other as BorderDirectionalAttribute; // cast the other instance + + return BorderDirectionalAttribute( + start: start?.merge(otherAttribute.start) ?? otherAttribute.start, + end: end?.merge(otherAttribute.end) ?? otherAttribute.end, + top: top?.merge(other.top) ?? other.top, + bottom: bottom?.merge(other.bottom) ?? other.bottom, + ); + } + + @override + BorderDirectional resolve(MixData mix) { + return BorderDirectional( + top: top?.resolve(mix) ?? BorderSide.none, + start: start?.resolve(mix) ?? BorderSide.none, + end: end?.resolve(mix) ?? BorderSide.none, + bottom: bottom?.resolve(mix) ?? BorderSide.none, + ); + } + + @override + List get props => [top, bottom, start, end]; +} + +@immutable +class BorderSideAttribute extends VisualAttribute { + final ColorAttribute? color; + final double? width; + final BorderStyle? style; + final double? strokeAlign; + + const BorderSideAttribute({ + this.color, + this.strokeAlign, + this.style, + this.width, + }); + + BorderSideAttribute copyWith({ + ColorAttribute? color, + double? width, + BorderStyle? style, + double? strokeAlign, + }) { + return BorderSideAttribute( + color: color ?? this.color, + strokeAlign: strokeAlign ?? this.strokeAlign, + style: style ?? this.style, + width: width ?? this.width, + ); + } + + @override + BorderSideAttribute merge(BorderSideAttribute? other) { + if (other == null) return this; + + return BorderSideAttribute( + color: color?.merge(other.color) ?? other.color, + strokeAlign: other.strokeAlign ?? strokeAlign, + style: other.style ?? style, + width: other.width ?? width, + ); + } + + @override + BorderSide resolve(MixData mix) { + const defaultValue = BorderSide(); + + return BorderSide( + color: color?.resolve(mix) ?? defaultValue.color, + width: width ?? defaultValue.width, + style: style ?? defaultValue.style, + strokeAlign: strokeAlign ?? defaultValue.strokeAlign, + ); + } + + @override + get props => [color, width, style, strokeAlign]; +} diff --git a/lib/src/attributes/border/border_radius_attribute.dart b/lib/src/attributes/border/border_radius_attribute.dart new file mode 100644 index 000000000..196368a3d --- /dev/null +++ b/lib/src/attributes/border/border_radius_attribute.dart @@ -0,0 +1,256 @@ +import 'package:flutter/material.dart'; + +import '../../factory/mix_provider_data.dart'; +import '../attribute.dart'; + +@immutable +abstract class BorderRadiusGeometryAttribute + extends VisualAttribute { + final Radius? topLeft; + final Radius? topRight; + final Radius? bottomLeft; + final Radius? bottomRight; + + // Directional values + final Radius? topStart; + final Radius? topEnd; + final Radius? bottomStart; + final Radius? bottomEnd; + + const BorderRadiusGeometryAttribute({ + this.topLeft, + this.topRight, + this.bottomLeft, + this.bottomRight, + this.topStart, + this.topEnd, + this.bottomStart, + this.bottomEnd, + }); + + @override + BorderRadiusGeometryAttribute merge( + covariant BorderRadiusGeometryAttribute? other, + ); + + @override + T resolve(MixData mix); + + @override + get props => [ + topLeft, + topRight, + bottomLeft, + bottomRight, + topStart, + topEnd, + bottomStart, + bottomEnd, + ]; +} + +@immutable +class BorderRadiusAttribute + extends BorderRadiusGeometryAttribute { + const BorderRadiusAttribute({ + super.topLeft, + super.topRight, + super.bottomLeft, + super.bottomRight, + }); + + const BorderRadiusAttribute.zero() : this.all(Radius.zero); + + const BorderRadiusAttribute.all(Radius radius) + : super( + topLeft: radius, + topRight: radius, + bottomLeft: radius, + bottomRight: radius, + ); + + BorderRadiusAttribute.circular(double radius) + : this.all(Radius.circular(radius)); + + const BorderRadiusAttribute.horizontal({Radius? left, Radius? right}) + : super( + topLeft: left, + topRight: right, + bottomLeft: left, + bottomRight: right, + ); + + factory BorderRadiusAttribute.positional( + Radius p1, [ + Radius? p2, + Radius? p3, + Radius? p4, + ]) { + Radius topLeft = p1; + Radius topRight = p1; + Radius bottomLeft = p1; + Radius bottomRight = p1; + + if (p2 != null) { + bottomRight = p2; + bottomLeft = p2; + } + + if (p3 != null) { + topLeft = p1; + topRight = p2!; + bottomLeft = p2; + bottomRight = p3; + } + + if (p4 != null) { + topLeft = p1; + topRight = p2!; + bottomLeft = p3!; + bottomRight = p4; + } + + return BorderRadiusAttribute( + topLeft: topLeft, + topRight: topRight, + bottomLeft: bottomLeft, + bottomRight: bottomRight, + ); + } + + const BorderRadiusAttribute.vertical({Radius? top, Radius? bottom}) + : super( + topLeft: top, + topRight: top, + bottomLeft: bottom, + bottomRight: bottom, + ); + + @override + BorderRadiusAttribute merge(BorderRadiusGeometryAttribute? other) { + if (other == null) return this; + + return BorderRadiusAttribute( + topLeft: other.topLeft ?? topLeft, + topRight: other.topRight ?? topRight, + bottomLeft: other.bottomLeft ?? bottomLeft, + bottomRight: other.bottomRight ?? bottomRight, + ); + } + + @override + BorderRadius resolve(MixData mix) { + return BorderRadius.only( + topLeft: topLeft ?? Radius.zero, + topRight: topRight ?? Radius.zero, + bottomLeft: bottomLeft ?? Radius.zero, + bottomRight: bottomRight ?? Radius.zero, + ); + } +} + +@immutable +class BorderRadiusDirectionalAttribute + extends BorderRadiusGeometryAttribute { + const BorderRadiusDirectionalAttribute({ + super.topStart, + super.topEnd, + super.bottomStart, + super.bottomEnd, + }); + + factory BorderRadiusDirectionalAttribute.positional( + Radius p1, [ + Radius? p2, + Radius? p3, + Radius? p4, + ]) { + Radius topStart = p1; + Radius topEnd = p1; + Radius bottomStart = p1; + Radius bottomEnd = p1; + + if (p2 != null) { + bottomEnd = p2; + bottomStart = p2; + } + + if (p3 != null) { + topStart = p1; + topEnd = p2!; + bottomStart = p2; + bottomEnd = p3; + } + + if (p4 != null) { + topStart = p1; + topEnd = p2!; + bottomStart = p3!; + bottomEnd = p4; + } + + return BorderRadiusDirectionalAttribute( + topStart: topStart, + topEnd: topEnd, + bottomStart: bottomStart, + bottomEnd: bottomEnd, + ); + } + + BorderRadiusDirectionalAttribute.circular(double radius) + : this.all(Radius.circular(radius)); + + const BorderRadiusDirectionalAttribute.zero() : this.all(Radius.zero); + + const BorderRadiusDirectionalAttribute.all(Radius radius) + : super( + topStart: radius, + topEnd: radius, + bottomStart: radius, + bottomEnd: radius, + ); + + const BorderRadiusDirectionalAttribute.horizontal({ + Radius? start, + Radius? end, + }) : super( + topStart: start, + topEnd: end, + bottomStart: start, + bottomEnd: end, + ); + + const BorderRadiusDirectionalAttribute.vertical({ + Radius? top, + Radius? bottom, + }) : super( + topStart: top, + topEnd: top, + bottomStart: bottom, + bottomEnd: bottom, + ); + + @override + BorderRadiusDirectionalAttribute merge( + BorderRadiusGeometryAttribute? other, + ) { + if (other == null) return this; + + return BorderRadiusDirectionalAttribute( + topStart: other.topStart ?? topStart, + topEnd: other.topEnd ?? topEnd, + bottomStart: other.bottomStart ?? bottomStart, + bottomEnd: other.bottomEnd ?? bottomEnd, + ); + } + + @override + BorderRadiusDirectional resolve(MixData mix) { + return BorderRadiusDirectional.only( + topStart: topStart ?? Radius.zero, + topEnd: topEnd ?? Radius.zero, + bottomStart: bottomStart ?? Radius.zero, + bottomEnd: bottomEnd ?? Radius.zero, + ); + } +} diff --git a/lib/src/attributes/color_attribute.dart b/lib/src/attributes/color_attribute.dart new file mode 100644 index 000000000..b3801ab5a --- /dev/null +++ b/lib/src/attributes/color_attribute.dart @@ -0,0 +1,38 @@ +import 'package:flutter/material.dart'; + +import '../factory/mix_provider_data.dart'; +import '../theme/tokens/color_token.dart'; +import 'attribute.dart'; + +@immutable +class ColorAttribute extends ScalarAttribute { + const ColorAttribute(super.value); + + @override + ColorAttribute create(Color value) => ColorAttribute(value); + + @override + Color resolve(MixData mix) { + final resolvedColor = value; + + return resolvedColor is ColorToken + ? mix.resolver.colorToken(resolvedColor) + : resolvedColor; + } +} + +@immutable +class IconColorAttribute extends ColorAttribute { + const IconColorAttribute(super.color); + + @override + IconColorAttribute create(value) => IconColorAttribute(value); +} + +@immutable +class ImageColorAttribute extends ColorAttribute { + const ImageColorAttribute(super.color); + + @override + ImageColorAttribute create(value) => ImageColorAttribute(value); +} diff --git a/lib/src/attributes/constraints_attribute.dart b/lib/src/attributes/constraints_attribute.dart new file mode 100644 index 000000000..66e3c5ef1 --- /dev/null +++ b/lib/src/attributes/constraints_attribute.dart @@ -0,0 +1,77 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; + +import '../factory/mix_provider_data.dart'; +import 'attribute.dart'; + +@immutable +abstract class ConstraintsAttribute + extends VisualAttribute { + const ConstraintsAttribute(); + + @override + ConstraintsAttribute merge(covariant ConstraintsAttribute? other); + + @override + T resolve(MixData mix); +} + +@immutable +class BoxConstraintsAttribute extends ConstraintsAttribute { + final double? width; + final double? height; + final double? minWidth; + final double? maxWidth; + final double? minHeight; + final double? maxHeight; + + const BoxConstraintsAttribute({ + this.width, + this.height, + this.minWidth, + this.maxWidth, + this.minHeight, + this.maxHeight, + }); + + @override + BoxConstraintsAttribute merge(covariant BoxConstraintsAttribute? other) { + if (other == null) return this; + + return BoxConstraintsAttribute( + width: other.width ?? width, + height: other.height ?? height, + minWidth: other.minWidth ?? minWidth, + maxWidth: other.maxWidth ?? maxWidth, + minHeight: other.minHeight ?? minHeight, + maxHeight: other.maxHeight ?? maxHeight, + ); + } + + @override + BoxConstraints resolve(MixData mix) { + BoxConstraints? constraints; + + if (minWidth != null || + maxWidth != null || + minHeight != null || + maxHeight != null) { + constraints = BoxConstraints( + minWidth: minWidth ?? 0, + maxWidth: maxWidth ?? double.infinity, + minHeight: minHeight ?? 0, + maxHeight: maxHeight ?? double.infinity, + ); + } + + constraints = (width != null || height != null) + ? constraints?.tighten(width: width, height: height) ?? + BoxConstraints.tightFor(width: width, height: height) + : constraints; + + return constraints ?? const BoxConstraints(); + } + + @override + get props => [minWidth, maxWidth, minHeight, maxHeight]; +} diff --git a/lib/src/attributes/decoration_attribute.dart b/lib/src/attributes/decoration_attribute.dart new file mode 100644 index 000000000..58ea9c8e6 --- /dev/null +++ b/lib/src/attributes/decoration_attribute.dart @@ -0,0 +1,125 @@ +// ignore_for_file: no_leading_underscores_for_local_identifiers + +import 'package:flutter/material.dart'; + +import '../factory/mix_provider_data.dart'; +import 'attribute.dart'; +import 'border/border_attribute.dart'; +import 'border/border_radius_attribute.dart'; +import 'color_attribute.dart'; +import 'scalar_attribute.dart'; +import 'shadow_attribute.dart'; + +@immutable +abstract class DecorationAttribute + extends VisualAttribute { + const DecorationAttribute(); + + @override + DecorationAttribute merge(covariant DecorationAttribute? other); + + @override + T resolve(MixData mix); +} + +@immutable +class BoxDecorationAttribute extends DecorationAttribute { + final ColorAttribute? color; + final BoxBorderAttribute? border; + final BorderRadiusGeometryAttribute? borderRadius; + final GradientAttribute? gradient; + final List? boxShadow; + final BoxShapeAttribute? shape; + const BoxDecorationAttribute({ + this.border, + this.borderRadius, + this.gradient, + this.boxShadow, + this.color, + this.shape, + }); + + @override + BoxDecorationAttribute merge(BoxDecorationAttribute? other) { + if (other == null) return this; + + return BoxDecorationAttribute( + border: border?.merge(other.border) ?? other.border, + borderRadius: + borderRadius?.merge(other.borderRadius) ?? other.borderRadius, + gradient: gradient?.merge(other.gradient) ?? other.gradient, + boxShadow: mergeMergeableList(boxShadow, other.boxShadow), + color: color?.merge(other.color) ?? other.color, + shape: other.shape ?? shape, + ); + } + + @override + BoxDecoration resolve(MixData mix) { + return BoxDecoration( + color: color?.resolve(mix), + border: border?.resolve(mix), + borderRadius: borderRadius?.resolve(mix), + boxShadow: boxShadow?.map((e) => e.resolve(mix)).toList(), + gradient: gradient?.resolve(mix), + ); + } + + @override + get props => [border, borderRadius, gradient, boxShadow, color, shape]; +} + +@immutable +class ShapeDecorationAttribute extends DecorationAttribute { + // The color to fill in the background of the shape. + final ColorAttribute? color; + + // The shape of the box. + final ShapeBorder? shape; + // A gradient to use when filling the box. + final GradientAttribute? gradient; + + // Shadows cast by this box behind the box. + final List? boxShadow; + + const ShapeDecorationAttribute({ + this.color, + this.shape, + this.gradient, + this.boxShadow, + }); + + @override + ShapeDecorationAttribute merge(ShapeDecorationAttribute? other) { + if (other == null) return this; + + return ShapeDecorationAttribute( + color: color?.merge(other.color) ?? other.color, + shape: other.shape ?? shape, + gradient: gradient?.merge(other.gradient) ?? other.gradient, + boxShadow: mergeMergeableList(boxShadow, other.boxShadow), + ); + } + + @override + ShapeDecoration resolve(MixData mix) { + return ShapeDecoration( + color: color?.resolve(mix), + gradient: gradient?.resolve(mix), + shadows: boxShadow?.map((e) => e.resolve(mix)).toList(), + shape: shape ?? const RoundedRectangleBorder(), + ); + } + + @override + List get props => [color, shape, gradient, boxShadow]; +} + +class ForegroundDecorationAttribute + extends ScalarAttribute { + const ForegroundDecorationAttribute(super.value); + + @override + ForegroundDecorationAttribute create(value) => + ForegroundDecorationAttribute(value); +} diff --git a/lib/src/attributes/edge_insets_attribute.dart b/lib/src/attributes/edge_insets_attribute.dart new file mode 100644 index 000000000..64046992c --- /dev/null +++ b/lib/src/attributes/edge_insets_attribute.dart @@ -0,0 +1,100 @@ +// ignore_for_file: avoid-shadowing + +import 'package:flutter/material.dart'; + +import '../factory/mix_provider_data.dart'; +import 'attribute.dart'; + +@immutable +abstract class EdgeInsetsGeometryAttribute + extends VisualAttribute { + final double? top; + final double? bottom; + final double? left; + final double? right; + + // Directional + final double? start; + final double? end; + + const EdgeInsetsGeometryAttribute({ + this.top, + this.bottom, + this.left, + this.right, + this.start, + this.end, + }); + + @override + EdgeInsetsGeometryAttribute merge( + covariant EdgeInsetsGeometryAttribute? other, + ); + + @override + T resolve(MixData mix); + + @override + get props => [top, bottom, left, right, start, end]; +} + +@immutable +class EdgeInsetsAttribute extends EdgeInsetsGeometryAttribute { + const EdgeInsetsAttribute({ + super.top, + super.bottom, + super.left, + super.right, + }); + + @override + EdgeInsetsAttribute merge(EdgeInsetsAttribute? other) { + return EdgeInsetsAttribute( + top: other?.top ?? top, + bottom: other?.bottom ?? bottom, + left: other?.left ?? left, + right: other?.right ?? right, + ); + } + + @override + EdgeInsets resolve(MixData mix) { + return EdgeInsets.only( + left: left ?? 0, + top: top ?? 0, + right: right ?? 0, + bottom: bottom ?? 0, + ); + } +} + +@immutable +class EdgeInsetsDirectionalAttribute + extends EdgeInsetsGeometryAttribute { + const EdgeInsetsDirectionalAttribute({ + super.top, + super.bottom, + super.start, + super.end, + }); + + @override + EdgeInsetsDirectionalAttribute merge(EdgeInsetsDirectionalAttribute? other) { + return EdgeInsetsDirectionalAttribute( + top: other?.top ?? top, + bottom: other?.bottom ?? bottom, + start: other?.start ?? start, + end: other?.end ?? end, + ); + } + + @override + EdgeInsetsDirectional resolve(MixData mix) { + return EdgeInsetsDirectional.only( + start: start ?? 0, + top: top ?? 0, + end: end ?? 0, + bottom: bottom ?? 0, + ); + } +} diff --git a/lib/src/attributes/exports.dart b/lib/src/attributes/exports.dart deleted file mode 100644 index 739af1465..000000000 --- a/lib/src/attributes/exports.dart +++ /dev/null @@ -1,5 +0,0 @@ -export 'attribute.dart'; -export 'helpers/helper.utils.dart'; -export 'shared/shared.attributes.dart'; -export 'shared/shared.utilities.dart'; -export 'shared/shared.descriptor.dart'; diff --git a/lib/src/attributes/helpers/helper.utils.dart b/lib/src/attributes/helpers/helper.utils.dart deleted file mode 100644 index 5fea4f7e0..000000000 --- a/lib/src/attributes/helpers/helper.utils.dart +++ /dev/null @@ -1,68 +0,0 @@ -import '../../factory/style_mix.dart'; -import '../nested_attribute.dart'; - -@Deprecated('Use style.merge(otherStyle), instead') -class HelperUtility { - const HelperUtility._(); - - @Deprecated('Use style.merge(otherStyle), instead') - static NestedStyleAttribute apply( - List mixes, - ) { - return NestedStyleAttribute(StyleMix.combine(mixes)); - } -} - -typedef FunctionWithListParam = ReturnType Function( - List params, -); - -typedef FunctionWithMapParam, ReturnType> - = ReturnType Function( - ParamType params, -); - -class SpreadNamedParams, ReturnType> { - final FunctionWithMapParam _function; - final Map _initialParams; - - SpreadNamedParams( - this._function, { - ParamType? initialParams, - }) : _initialParams = initialParams ?? {}; - - ReturnType call({ParamType? additionalParams}) { - final params = {..._initialParams, ...?additionalParams} as ParamType; - - return _function(params); - } -} - -class SpreadPositionalParams { - const SpreadPositionalParams(this.fn); - - final FunctionWithListParam fn; - - // ignore: long-parameter-list - ReturnType call([ - ParamType? p1, - ParamType? p2, - ParamType? p3, - ParamType? p4, - ParamType? p5, - ParamType? p6, - ParamType? p7, - ParamType? p8, - ParamType? p9, - ParamType? p10, - ParamType? p11, - ParamType? p12, - ]) { - final params = []; - for (final param in [p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12]) { - if (param != null) params.add(param); - } - - return fn(params); - } -} diff --git a/lib/src/attributes/nested_attribute.dart b/lib/src/attributes/nested_attribute.dart deleted file mode 100644 index 41ccbc5e8..000000000 --- a/lib/src/attributes/nested_attribute.dart +++ /dev/null @@ -1,20 +0,0 @@ -import '../factory/style_mix.dart'; -import 'attribute.dart'; - -/// Allows to pass down Mixes as attributes for use with helpers -class NestedStyleAttribute extends StyleAttribute - with Mergeable { - const NestedStyleAttribute(this.style); - - final StyleMix style; - - @override - NestedStyleAttribute merge(NestedStyleAttribute? other) { - if (other == null) return this; - - return NestedStyleAttribute(style.merge(other.style)); - } - - @override - get props => [style]; -} diff --git a/lib/src/attributes/scalar_attribute.dart b/lib/src/attributes/scalar_attribute.dart new file mode 100644 index 000000000..c43bf10d3 --- /dev/null +++ b/lib/src/attributes/scalar_attribute.dart @@ -0,0 +1,240 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import 'attribute.dart'; + +class AxisAttribute extends ScalarAttribute { + const AxisAttribute(super.value); + + @override + AxisAttribute create(value) => AxisAttribute(value); +} + +class GradientAttribute extends ScalarAttribute { + const GradientAttribute(super.value); + + @override + GradientAttribute create(value) => GradientAttribute(value); +} + +class MainAxisAlignmentAttribute + extends ScalarAttribute { + const MainAxisAlignmentAttribute(super.value); + + @override + MainAxisAlignmentAttribute create(value) => MainAxisAlignmentAttribute(value); +} + +class TransformAlignmentAttribute + extends ScalarAttribute { + const TransformAlignmentAttribute(super.value); + + @override + TransformAlignmentAttribute create(value) => + TransformAlignmentAttribute(value); +} + +class MainAxisSizeAttribute + extends ScalarAttribute { + const MainAxisSizeAttribute(super.value); + + @override + MainAxisSizeAttribute create(value) => MainAxisSizeAttribute(value); +} + +class CrossAxisAlignmentAttribute + extends ScalarAttribute { + const CrossAxisAlignmentAttribute(super.value); + + @override + CrossAxisAlignmentAttribute create(value) => + CrossAxisAlignmentAttribute(value); +} + +class VerticalDirectionAttribute + extends ScalarAttribute { + const VerticalDirectionAttribute(super.value); + + @override + VerticalDirectionAttribute create(value) => VerticalDirectionAttribute(value); +} + +class TextBaselineAttribute + extends ScalarAttribute { + const TextBaselineAttribute(super.value); + + @override + TextBaselineAttribute create(value) => TextBaselineAttribute(value); +} + +class ClipAttribute extends ScalarAttribute { + const ClipAttribute(super.value); + + @override + ClipAttribute create(value) => ClipAttribute(value); +} + +class ImageAlignmentAttribute + extends ScalarAttribute { + const ImageAlignmentAttribute(super.value); + + @override + ImageAlignmentAttribute create(value) => ImageAlignmentAttribute(value); +} + +class ImageScaleAttribute extends ScalarAttribute { + const ImageScaleAttribute(super.value); + + @override + ImageScaleAttribute create(value) => ImageScaleAttribute(value); +} + +class ImageFitAttribute extends ScalarAttribute { + const ImageFitAttribute(super.value); + + @override + ImageFitAttribute create(value) => ImageFitAttribute(value); +} + +class ImageRepeatAttribute + extends ScalarAttribute { + const ImageRepeatAttribute(super.value); + + @override + ImageRepeatAttribute create(value) => ImageRepeatAttribute(value); +} + +class ImageWidthAttribute extends ScalarAttribute { + const ImageWidthAttribute(super.value); + + @override + ImageWidthAttribute create(value) => ImageWidthAttribute(value); +} + +class ImageHeightAttribute + extends ScalarAttribute { + const ImageHeightAttribute(super.value); + + @override + ImageHeightAttribute create(value) => ImageHeightAttribute(value); +} + +class TextAlignAttribute + extends ScalarAttribute { + const TextAlignAttribute(super.value); + + @override + TextAlignAttribute create(value) => TextAlignAttribute(value); +} + +class TextDirectionAttribute + extends ScalarAttribute { + const TextDirectionAttribute(super.value); + + @override + TextDirectionAttribute create(value) => TextDirectionAttribute(value); +} + +class SoftWrapAttribute extends ScalarAttribute { + const SoftWrapAttribute(super.value); + + @override + SoftWrapAttribute create(value) => SoftWrapAttribute(value); +} + +class TextOverflowAttribute + extends ScalarAttribute { + const TextOverflowAttribute(super.value); + + @override + TextOverflowAttribute create(value) => TextOverflowAttribute(value); +} + +class TextScaleFactorAttribute + extends ScalarAttribute { + const TextScaleFactorAttribute(super.value); + + @override + TextScaleFactorAttribute create(value) => TextScaleFactorAttribute(value); +} + +class MaxLinesAttribute extends ScalarAttribute { + const MaxLinesAttribute(super.value); + + @override + MaxLinesAttribute create(value) => MaxLinesAttribute(value); +} + +class TextWidthBasisAttribute + extends ScalarAttribute { + const TextWidthBasisAttribute(super.value); + + @override + TextWidthBasisAttribute create(value) => TextWidthBasisAttribute(value); +} + +class TextHeightBehaviorAttribute + extends ScalarAttribute { + const TextHeightBehaviorAttribute(super.value); + + @override + TextHeightBehaviorAttribute create(value) => + TextHeightBehaviorAttribute(value); +} + +class IconSizeAttribute extends ScalarAttribute { + const IconSizeAttribute(super.value); + + @override + IconSizeAttribute create(value) => IconSizeAttribute(value); +} + +class BoxFitAttribute extends ScalarAttribute { + const BoxFitAttribute(super.value); + + @override + BoxFitAttribute create(value) => BoxFitAttribute(value); +} + +class StackFitAttribute extends ScalarAttribute { + const StackFitAttribute(super.value); + + @override + StackFitAttribute create(value) => StackFitAttribute(value); +} + +class FlexFitAttribute extends ScalarAttribute { + const FlexFitAttribute(super.value); + + @override + FlexFitAttribute create(value) => FlexFitAttribute(value); +} + +class TransformAttribute extends ScalarAttribute { + const TransformAttribute(super.value); + + @override + TransformAttribute create(value) => TransformAttribute(value); +} + +class BlendModeAttribute + extends ScalarAttribute { + const BlendModeAttribute(super.value); + + @override + BlendModeAttribute create(value) => BlendModeAttribute(value); +} + +class BoxShapeAttribute extends ScalarAttribute { + const BoxShapeAttribute(super.value); + + @override + BoxShapeAttribute create(value) => BoxShapeAttribute(value); +} + +class VisibleAttribute extends ScalarAttribute { + const VisibleAttribute(super.value); + + @override + VisibleAttribute create(value) => VisibleAttribute(value); +} diff --git a/lib/src/attributes/shadow_attribute.dart b/lib/src/attributes/shadow_attribute.dart new file mode 100644 index 000000000..81b3624eb --- /dev/null +++ b/lib/src/attributes/shadow_attribute.dart @@ -0,0 +1,75 @@ +import 'package:flutter/material.dart'; + +import '../factory/mix_provider_data.dart'; +import 'attribute.dart'; +import 'color_attribute.dart'; + +@immutable +class ShadowAttribute extends VisualAttribute { + final ColorAttribute? color; + final Offset? offset; + final double? blurRadius; + + const ShadowAttribute({this.blurRadius, this.color, this.offset}); + + @override + Shadow resolve(MixData mix) { + const defaultShadow = Shadow(); + + return Shadow( + color: color?.resolve(mix) ?? defaultShadow.color, + offset: offset ?? defaultShadow.offset, + blurRadius: blurRadius ?? defaultShadow.blurRadius, + ); + } + + @override + ShadowAttribute merge(ShadowAttribute? other) { + return ShadowAttribute( + blurRadius: other?.blurRadius ?? blurRadius, + color: color?.merge(other?.color) ?? other?.color, + offset: other?.offset ?? offset, + ); + } + + @override + get props => [color, offset, blurRadius]; +} + +class BoxShadowAttribute extends ShadowAttribute { + final double? spreadRadius; + + const BoxShadowAttribute({ + super.color, + super.offset, + super.blurRadius, + this.spreadRadius, + }); + + @override + BoxShadow resolve(MixData mix) { + const defaultShadow = BoxShadow(); + + final shadow = super.resolve(mix); + + return BoxShadow( + color: shadow.color, + offset: shadow.offset, + blurRadius: shadow.blurRadius, + spreadRadius: spreadRadius ?? defaultShadow.spreadRadius, + ); + } + + @override + BoxShadowAttribute merge(BoxShadowAttribute? other) { + return BoxShadowAttribute( + color: color?.merge(other?.color) ?? other?.color, + offset: other?.offset ?? offset, + blurRadius: other?.blurRadius ?? blurRadius, + spreadRadius: other?.spreadRadius ?? spreadRadius, + ); + } + + @override + get props => [...super.props, spreadRadius]; +} diff --git a/lib/src/attributes/shared/shared.attributes.dart b/lib/src/attributes/shared/shared.attributes.dart deleted file mode 100644 index f4e75889e..000000000 --- a/lib/src/attributes/shared/shared.attributes.dart +++ /dev/null @@ -1,59 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../attribute.dart'; - -class SharedStyleAttributes extends StyledWidgetAttributes { - final bool? visible; - //Animation - final bool? animated; - final Duration? animationDuration; - final Curve? animationCurve; - final TextDirection? textDirection; - - const SharedStyleAttributes({ - this.visible, - this.animated, - this.animationDuration, - this.animationCurve, - this.textDirection, - }); - - @override - SharedStyleAttributes merge(SharedStyleAttributes? other) { - if (other == null) return this; - - return copyWith( - visible: other.visible, - animated: other.animated, - animationDuration: other.animationDuration, - animationCurve: other.animationCurve, - textDirection: other.textDirection, - ); - } - - @override - SharedStyleAttributes copyWith({ - bool? visible, - bool? animated, - Duration? animationDuration, - Curve? animationCurve, - TextDirection? textDirection, - }) { - return SharedStyleAttributes( - visible: visible ?? this.visible, - animated: animated ?? this.animated, - animationDuration: animationDuration ?? this.animationDuration, - animationCurve: animationCurve ?? this.animationCurve, - textDirection: textDirection ?? this.textDirection, - ); - } - - @override - get props => [ - visible, - animated, - animationDuration, - animationCurve, - textDirection, - ]; -} diff --git a/lib/src/attributes/shared/shared.descriptor.dart b/lib/src/attributes/shared/shared.descriptor.dart deleted file mode 100644 index 99d7012db..000000000 --- a/lib/src/attributes/shared/shared.descriptor.dart +++ /dev/null @@ -1,57 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../../factory/mix_provider_data.dart'; -import 'shared.attributes.dart'; - -class CommonDescriptor { - final bool visible; - //Animation - final bool animated; - final Duration animationDuration; - final Curve animationCurve; - final TextDirection? textDirection; - - const CommonDescriptor({ - required this.visible, - required this.animated, - required this.animationDuration, - required this.animationCurve, - this.textDirection, - }); - - factory CommonDescriptor.fromContext(MixData mix) { - final common = mix.attributesOfType(); - - return CommonDescriptor( - visible: common?.visible ?? true, - animated: common?.animated ?? false, - animationDuration: common?.animationDuration ?? - const Duration( - milliseconds: 100, - ), - animationCurve: common?.animationCurve ?? Curves.linear, - textDirection: common?.textDirection, - ); - } - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - - return other is CommonDescriptor && - other.visible == visible && - other.animated == animated && - other.animationDuration == animationDuration && - other.animationCurve == animationCurve && - other.textDirection == textDirection; - } - - @override - int get hashCode { - return visible.hashCode ^ - animated.hashCode ^ - animationDuration.hashCode ^ - animationCurve.hashCode ^ - textDirection.hashCode; - } -} diff --git a/lib/src/attributes/shared/shared.utilities.dart b/lib/src/attributes/shared/shared.utilities.dart deleted file mode 100644 index e3baff3db..000000000 --- a/lib/src/attributes/shared/shared.utilities.dart +++ /dev/null @@ -1,47 +0,0 @@ -import 'package:flutter/material.dart'; - -import 'shared.attributes.dart'; - -class CommonUtility { - const CommonUtility._(); - - static SharedStyleAttributes animation({ - Curve? curve, - int? duration, - Duration? asDuration, - }) { - return SharedStyleAttributes( - animated: true, - animationCurve: curve, - animationDuration: - // Prioritize duration in milliseconds - duration != null ? Duration(milliseconds: duration) : asDuration, - ); - } - - static SharedStyleAttributes animationDuration(int milliseconds) { - return SharedStyleAttributes( - animated: true, - animationDuration: Duration( - milliseconds: milliseconds, - ), - ); - } - - static SharedStyleAttributes animationCurve(Curve curve) { - return SharedStyleAttributes( - animated: true, - animationCurve: curve, - ); - } - - static SharedStyleAttributes textDirection(TextDirection? textDirection) { - return SharedStyleAttributes(textDirection: textDirection); - } - - static SharedStyleAttributes visible([bool? condition = true]) => - SharedStyleAttributes(visible: condition); - - static SharedStyleAttributes hidden([bool condition = true]) => - SharedStyleAttributes(visible: !condition); -} diff --git a/lib/src/attributes/space_attribute.dart b/lib/src/attributes/space_attribute.dart new file mode 100644 index 000000000..88b82cd1d --- /dev/null +++ b/lib/src/attributes/space_attribute.dart @@ -0,0 +1,231 @@ +// ignore_for_file: avoid-shadowing + +import 'package:flutter/material.dart'; + +import '../factory/mix_provider_data.dart'; +import 'attribute.dart'; + +@immutable +abstract class SpaceGeometryAttribute + extends VisualAttribute { + final double? top; + final double? bottom; + final double? left; + final double? right; + + // Directional + final double? start; + final double? end; + + const SpaceGeometryAttribute({ + this.top, + this.bottom, + this.left, + this.right, + this.start, + this.end, + }); + + SpaceGeometryAttribute create({ + double? top, + double? bottom, + double? left, + double? right, + double? start, + double? end, + }); + + @override + SpaceGeometryAttribute merge( + covariant SpaceGeometryAttribute? other, + ) { + return create( + top: other?.top ?? top, + bottom: other?.bottom ?? bottom, + left: other?.left ?? left, + right: other?.right ?? right, + start: other?.start ?? start, + end: other?.end ?? end, + ); + } + + @override + T resolve(MixData mix) { + final top = this.top ?? 0; + final bottom = this.bottom ?? 0; + + if (this is SpaceAttribute) { + final left = this.left ?? 0; + final right = this.right ?? 0; + + return EdgeInsets.only( + left: mix.resolver.spaceTokenRef(left), + top: mix.resolver.spaceTokenRef(top), + right: mix.resolver.spaceTokenRef(right), + bottom: mix.resolver.spaceTokenRef(bottom), + ) as T; + } else if (this is SpaceDirectionalAttribute) { + final start = this.start ?? 0; + final end = this.end ?? 0; + + return EdgeInsetsDirectional.only( + start: mix.resolver.spaceTokenRef(start), + top: mix.resolver.spaceTokenRef(top), + end: mix.resolver.spaceTokenRef(end), + bottom: mix.resolver.spaceTokenRef(bottom), + ) as T; + } + throw UnsupportedError( + 'SpaceGeometryAttribute must be either SpaceAttribute or SpaceDirectionalAttribute', + ); + } + + @override + get props => [top, bottom, left, right, start, end]; +} + +@immutable +abstract class SpaceAttribute extends SpaceGeometryAttribute { + const SpaceAttribute({super.top, super.bottom, super.left, super.right}); +} + +@immutable +abstract class SpaceDirectionalAttribute + extends SpaceGeometryAttribute { + const SpaceDirectionalAttribute({ + super.top, + super.bottom, + super.start, + super.end, + }); +} + +@immutable +abstract class PaddingGeometryAttribute + extends SpaceGeometryAttribute { + const PaddingGeometryAttribute({ + super.top, + super.bottom, + super.left, + super.right, + super.start, + super.end, + }); +} + +@immutable +class PaddingAttribute extends PaddingGeometryAttribute + implements SpaceAttribute { + const PaddingAttribute({super.top, super.bottom, super.left, super.right}); + + @override + PaddingAttribute create({ + double? top, + double? bottom, + double? left, + double? right, + double? start, + double? end, + }) { + return PaddingAttribute( + top: top ?? this.top, + bottom: bottom ?? this.bottom, + left: left ?? this.left, + right: right ?? this.right, + ); + } +} + +@immutable +class PaddingDirectionalAttribute + extends PaddingGeometryAttribute + implements SpaceDirectionalAttribute { + const PaddingDirectionalAttribute({ + super.top, + super.bottom, + super.start, + super.end, + }); + + @override + PaddingDirectionalAttribute create({ + double? top, + double? bottom, + double? left, + double? right, + double? start, + double? end, + }) { + return PaddingDirectionalAttribute( + top: top ?? this.top, + bottom: bottom ?? this.bottom, + start: start ?? this.start, + end: end ?? this.end, + ); + } +} + +@immutable +abstract class MarginGeometryAttribute + extends SpaceGeometryAttribute { + const MarginGeometryAttribute({ + super.top, + super.bottom, + super.left, + super.right, + super.start, + super.end, + }); +} + +@immutable +class MarginAttribute extends MarginGeometryAttribute + implements SpaceAttribute { + const MarginAttribute({super.top, super.bottom, super.left, super.right}); + + @override + MarginAttribute create({ + double? top, + double? bottom, + double? left, + double? right, + double? start, + double? end, + }) { + return MarginAttribute( + top: top ?? this.top, + bottom: bottom ?? this.bottom, + left: left ?? this.left, + right: right ?? this.right, + ); + } +} + +@immutable +class MarginDirectionalAttribute + extends MarginGeometryAttribute + implements SpaceDirectionalAttribute { + const MarginDirectionalAttribute({ + super.top, + super.bottom, + super.start, + super.end, + }); + + @override + MarginDirectionalAttribute create({ + double? top, + double? bottom, + double? left, + double? right, + double? start, + double? end, + }) { + return MarginDirectionalAttribute( + top: top ?? this.top, + bottom: bottom ?? this.bottom, + start: start ?? this.start, + end: end ?? this.end, + ); + } +} diff --git a/lib/src/attributes/strut_style_attribute.dart b/lib/src/attributes/strut_style_attribute.dart new file mode 100644 index 000000000..d92d52ecc --- /dev/null +++ b/lib/src/attributes/strut_style_attribute.dart @@ -0,0 +1,71 @@ +import 'package:flutter/material.dart'; + +import '../factory/mix_provider_data.dart'; +import 'attribute.dart'; + +@immutable +class StrutStyleAttribute extends VisualAttribute { + final String? fontFamily; + final List? fontFamilyFallback; + final double? fontSize; + final FontWeight? fontWeight; + final FontStyle? fontStyle; + final double? height; + final double? leading; + final bool? forceStrutHeight; + + const StrutStyleAttribute({ + this.fontFamily, + this.fontFamilyFallback, + this.fontSize, + this.fontWeight, + this.fontStyle, + this.height, + this.leading, + this.forceStrutHeight, + }); + + @override + StrutStyleAttribute merge(StrutStyleAttribute? other) { + if (other == null) return this; + + return StrutStyleAttribute( + fontFamily: other.fontFamily ?? fontFamily, + fontFamilyFallback: other.fontFamilyFallback ?? fontFamilyFallback, + fontSize: other.fontSize ?? fontSize, + fontWeight: other.fontWeight ?? fontWeight, + fontStyle: other.fontStyle ?? fontStyle, + height: other.height ?? height, + leading: other.leading ?? leading, + forceStrutHeight: other.forceStrutHeight ?? forceStrutHeight, + ); + } + + @override + StrutStyle resolve(MixData mix) { + const defaultValue = StrutStyle(); + + return StrutStyle( + fontFamily: fontFamily ?? defaultValue.fontFamily, + fontFamilyFallback: fontFamilyFallback ?? defaultValue.fontFamilyFallback, + fontSize: fontSize ?? defaultValue.fontSize, + height: height ?? defaultValue.height, + leading: leading ?? defaultValue.leading, + fontWeight: fontWeight ?? defaultValue.fontWeight, + fontStyle: fontStyle ?? defaultValue.fontStyle, + forceStrutHeight: forceStrutHeight ?? defaultValue.forceStrutHeight, + ); + } + + @override + get props => [ + fontFamily, + fontFamilyFallback, + fontSize, + fontWeight, + fontStyle, + height, + leading, + forceStrutHeight, + ]; +} diff --git a/lib/src/attributes/style_mix_attribute.dart b/lib/src/attributes/style_mix_attribute.dart new file mode 100644 index 000000000..03fda5bdc --- /dev/null +++ b/lib/src/attributes/style_mix_attribute.dart @@ -0,0 +1,19 @@ +import '../factory/style_mix.dart'; +import 'attribute.dart'; + +/// Allows to pass down Mixes as attributes for use with helpers. +class StyleMixAttribute extends Attribute { + final StyleMix value; + + const StyleMixAttribute(this.value); + + @override + StyleMixAttribute merge(StyleMixAttribute? other) { + if (other == null) return this; + + return StyleMixAttribute(value.merge(other.value)); + } + + @override + get props => [value]; +} diff --git a/lib/src/attributes/text_style_attribute.dart b/lib/src/attributes/text_style_attribute.dart new file mode 100644 index 000000000..47d146c7c --- /dev/null +++ b/lib/src/attributes/text_style_attribute.dart @@ -0,0 +1,160 @@ +import 'dart:ui'; + +import 'package:flutter/material.dart'; + +import '../factory/mix_provider_data.dart'; +import '../theme/tokens/text_style_token.dart'; +import 'attribute.dart'; +import 'color_attribute.dart'; +import 'shadow_attribute.dart'; + +@immutable +class TextStyleAttribute extends VisualAttribute { + final String? fontFamily; + final FontWeight? fontWeight; + final FontStyle? fontStyle; + final double? fontSize; + final double? letterSpacing; + final double? wordSpacing; + final TextBaseline? textBaseline; + final ColorAttribute? color; + final ColorAttribute? backgroundColor; + final List? shadows; + final List? fontFeatures; + final TextDecoration? decoration; + final ColorAttribute? decorationColor; + final TextDecorationStyle? decorationStyle; + final Locale? locale; + final String? debugLabel; + final double? height; + final Paint? foreground; + final Paint? background; + final double? decorationThickness; + final List? fontFamilyFallback; + + final TextStyleToken? ref; + + const TextStyleAttribute({ + this.background, + this.backgroundColor, + this.color, + this.debugLabel, + this.decoration, + this.decorationColor, + this.decorationStyle, + this.decorationThickness, + this.fontFamily, + this.fontFamilyFallback, + this.fontFeatures, + this.fontSize, + this.fontStyle, + this.fontWeight, + this.foreground, + this.height, + this.letterSpacing, + this.locale, + this.shadows, + this.ref, + this.textBaseline, + this.wordSpacing, + }); + + bool isRef() => ref != null; + + @override + TextStyleAttribute merge(TextStyleAttribute? other) { + if (other == null) return this; + + final haveRefs = ref == null || other.ref == null; + + assert( + haveRefs, + 'Cannot merge two different refs', + ); + + return TextStyleAttribute( + background: other.background ?? background, + backgroundColor: other.backgroundColor ?? backgroundColor, + color: other.color ?? color, + debugLabel: other.debugLabel ?? debugLabel, + decoration: other.decoration ?? decoration, + decorationColor: other.decorationColor ?? decorationColor, + decorationStyle: other.decorationStyle ?? decorationStyle, + decorationThickness: other.decorationThickness ?? decorationThickness, + fontFamily: other.fontFamily ?? fontFamily, + fontFamilyFallback: [ + ...?fontFamilyFallback, + ...?other.fontFamilyFallback, + ], + fontFeatures: other.fontFeatures ?? fontFeatures, + fontSize: other.fontSize ?? fontSize, + fontStyle: other.fontStyle ?? fontStyle, + fontWeight: other.fontWeight ?? fontWeight, + foreground: other.foreground ?? foreground, + height: other.height ?? height, + letterSpacing: other.letterSpacing ?? letterSpacing, + locale: other.locale ?? locale, + shadows: mergeMergeableList(shadows, other.shadows), + ref: other.ref ?? ref, + textBaseline: other.textBaseline ?? textBaseline, + wordSpacing: other.wordSpacing ?? wordSpacing, + ); + } + + @override + TextStyle resolve(MixData mix) { + // ignore: avoid-non-null-assertion + final textStyle = ref == null ? null : mix.resolver.textStyleToken(ref!); + + return textStyle ?? + TextStyle( + color: color?.resolve(mix), + backgroundColor: backgroundColor?.resolve(mix), + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + textBaseline: textBaseline, + height: height, + locale: locale, + foreground: foreground, + background: background, + shadows: shadows?.map((e) => e.resolve(mix)).toList(), + fontFeatures: fontFeatures, + decoration: decoration, + decorationColor: decorationColor?.resolve(mix), + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + debugLabel: debugLabel, + fontFamily: fontFamily, + fontFamilyFallback: fontFamilyFallback, + ); + } + + @override + get props => [ + fontFamily, + fontWeight, + fontStyle, + fontSize, + letterSpacing, + wordSpacing, + textBaseline, + color, + backgroundColor, + shadows, + fontFeatures, + decoration, + decorationColor, + decorationStyle, + debugLabel, + locale, + height, + background, + foreground, + decorationThickness, + fontFamilyFallback, + ref, + ]; +} diff --git a/lib/src/attributes/variant_attribute.dart b/lib/src/attributes/variant_attribute.dart new file mode 100644 index 000000000..8e10b099f --- /dev/null +++ b/lib/src/attributes/variant_attribute.dart @@ -0,0 +1,84 @@ +import 'package:flutter/material.dart'; + +import '../factory/style_mix.dart'; +import '../variants/context_variant.dart'; +import '../variants/multi_variant.dart'; +import '../variants/variant.dart'; +import 'attribute.dart'; + +@immutable +class VariantAttribute extends Attribute { + final T variant; + final StyleMix _style; + + const VariantAttribute(this.variant, StyleMix style) : _style = style; + + StyleMix get value => _style; + + @override + VariantAttribute merge(covariant VariantAttribute other) { + if (other.variant != variant) { + throw throwArgumentError(other); + } + + return VariantAttribute(variant, _style.merge(other._style)); + } + + @override + get props => [variant, value]; +} + +@immutable +class ContextVariantAttribute extends VariantAttribute { + const ContextVariantAttribute(super.variant, super.style); + + bool when(BuildContext context) => variant.when(context); + + @override + ContextVariantAttribute merge(ContextVariantAttribute other) { + if (other.variant != variant) { + throw throwArgumentError(other); + } + + return ContextVariantAttribute(variant, _style.merge(other._style)); + } +} + +ArgumentError throwArgumentError(T other) { + throw ArgumentError.value( + other.runtimeType, + 'other', + 'VariantAttribute must have the same variant', + ); +} + +@immutable +class MultiVariantAttribute extends VariantAttribute { + const MultiVariantAttribute(super.variant, super.style); + + bool when(BuildContext context) => variant.when(context); + + // Remove all variants in given a list + VariantAttribute remove(Iterable variantsToRemove) { + final variant = this.variant.remove(variantsToRemove); + if (variant is MultiVariant) { + return MultiVariantAttribute(variant, _style); + } else if (variant is ContextVariant) { + return ContextVariantAttribute(variant, _style); + } + + return VariantAttribute(variant, _style); + } + + bool matches(Iterable otherVariants) => + variant.matches(otherVariants); + + @override + MultiVariantAttribute merge(MultiVariantAttribute other) { + if (other.variant != variant) { + throw throwArgumentError(other); + } + + return MultiVariantAttribute(variant, _style.merge(other._style)); + } +} diff --git a/lib/src/core/attributes_map.dart b/lib/src/core/attributes_map.dart new file mode 100644 index 000000000..906d66a0d --- /dev/null +++ b/lib/src/core/attributes_map.dart @@ -0,0 +1,58 @@ +// ignore_for_file: prefer_collection_literals + +import 'dart:collection'; + +import 'package:flutter/cupertino.dart'; + +import '../attributes/attribute.dart'; +import '../helpers/extensions/iterable_ext.dart'; +import 'equality/compare_mixin.dart'; + +@immutable +class VisualAttributeMap with Comparable { + final LinkedHashMap? _attributeMap; + + VisualAttributeMap._(this._attributeMap); + + factory VisualAttributeMap(List attributes) { + final attributeMap = LinkedHashMap(); + for (final attribute in attributes) { + final type = attribute.runtimeType; + if (attributeMap.containsKey(type)) { + attributeMap[type] = attributeMap[type]!.merge(attribute); + } else { + attributeMap[type] = attribute; + } + } + + return VisualAttributeMap._(attributeMap); + } + + @protected + LinkedHashMap get map => + _attributeMap ?? LinkedHashMap(); + + int get length => map.length; + + bool get isEmpty => map.isEmpty; + + bool get isNotEmpty => map.isNotEmpty; + + Iterable get values => map.values; + + T? attributeOfType() => + map.values.whereType().firstMaybeNull; + + Iterable whereType() { + return map.values.whereType(); + } + + VisualAttributeMap merge(VisualAttributeMap other) { + final list = [...values, ...other.values]; + + return VisualAttributeMap(list); + } + + @override + List get props => [_attributeMap ?? {}]; +} diff --git a/lib/src/core/constants.dart b/lib/src/core/constants.dart new file mode 100644 index 000000000..f705a382b --- /dev/null +++ b/lib/src/core/constants.dart @@ -0,0 +1,2 @@ +const kShortAliasDeprecation = + 'Short aliases will be deprecated, you can create your own. Example: final p = padding;'; diff --git a/lib/src/helpers/equality_mixin/equality_mixin.dart b/lib/src/core/equality/compare_mixin.dart similarity index 67% rename from lib/src/helpers/equality_mixin/equality_mixin.dart rename to lib/src/core/equality/compare_mixin.dart index fe8b46784..b85189f2e 100644 --- a/lib/src/helpers/equality_mixin/equality_mixin.dart +++ b/lib/src/core/equality/compare_mixin.dart @@ -1,11 +1,11 @@ -import '../../extensions/helper_ext.dart'; +import '../../helpers/extensions/iterable_ext.dart'; import 'deep_collection_equality.dart'; /// Returns a `hashCode` for [props]. int _mapPropsToHashCode(Iterable? props) => _finish([...?props].fold(0, _combine)); -const DeepCollectionEquality _equality = DeepCollectionEquality(); +const _equality = DeepCollectionEquality(); /// Determines whether [list1] and [list2] are equal. bool _equals(List? list1, List? list2) { @@ -14,9 +14,9 @@ bool _equals(List? list1, List? list2) { final length = list1.length; if (length != list2.length) return false; - for (var i = 0; i < length; i++) { - final dynamic unit1 = list1[i]; - final dynamic unit2 = list2[i]; + for (int i = 0; i < length; i++) { + final unit1 = list1[i]; + final unit2 = list2[i]; if (_isEquatable(unit1) && _isEquatable(unit2)) { if (unit1 != unit2) return false; @@ -33,7 +33,7 @@ bool _equals(List? list1, List? list2) { } bool _isEquatable(dynamic object) { - return object is EqualityMixin; + return object is Comparable; } /// Jenkins Hash Functions @@ -42,8 +42,8 @@ int _combine(int hash, dynamic object) { if (object is Map) { object.keys .sorted((dynamic a, dynamic b) => a.hashCode - b.hashCode) - .forEach((dynamic key) { - hash = hash ^ _combine(hash, [key, object[key]]); + .forEach((key) { + hash = hash ^ _combine(hash, [key, object[key]]); }); return hash; @@ -60,26 +60,41 @@ int _combine(int hash, dynamic object) { } hash = 0x1fffffff & (hash + object.hashCode); - hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10)); + hash = 0x1fffffff & (hash + ((hash & 0x0007ffff) << 10)); return hash ^ (hash >> 6); } int _finish(int hash) { - hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3)); + hash = 0x1fffffff & (hash + ((hash & 0x03ffffff) << 3)); hash = hash ^ (hash >> 11); - return 0x1fffffff & (hash + ((0x00003fff & hash) << 15)); + return 0x1fffffff & (hash + ((hash & 0x00003fff) << 15)); } -/// Returns a string for [props]. -String mapPropsToString(Type runtimeType, List props) => - '$runtimeType(${props.map((prop) => prop.toString()).join(', ')})'; +/// Returns a string representation of [props] with property names and values. +/// Only includes properties that are not null. +String mapPropsToString(Type runtimeType, List props) { + final buffer = StringBuffer()..write('$runtimeType('); + + for (var value in props) { + if (value != null) { + if (buffer.length > runtimeType.toString().length + 1) { + buffer.write(', '); + } + buffer.write(value); + } + } + + buffer.write(')'); + + return buffer.toString(); +} /// A mixin that helps implement equality /// without needing to explicitly override [operator ==] and [hashCode]. -mixin EqualityMixin { +mixin Comparable { List get props; bool get stringify => true; @@ -87,7 +102,7 @@ mixin EqualityMixin { @override bool operator ==(Object other) { return identical(this, other) || - other is EqualityMixin && + other is Comparable && runtimeType == other.runtimeType && _equals(props, other.props); } @@ -98,16 +113,16 @@ mixin EqualityMixin { List getDiff(Object other) { final diff = []; - // Return if there are no diferences + // Return if there are no diferences. if (this == other) return diff; - if (other is EqualityMixin) { + if (other is Comparable) { final otherProps = other.props; final length = props.length; - for (var i = 0; i < length; i++) { - final dynamic unit1 = props[i]; - final dynamic unit2 = otherProps[i]; + for (int i = 0; i < length; i++) { + final unit1 = props[i]; + final unit2 = otherProps[i]; if (unit1 is Iterable || unit1 is Map) { if (!_equality.equals(unit1, unit2)) { @@ -128,10 +143,6 @@ mixin EqualityMixin { @override String toString() { - if (stringify) { - return mapPropsToString(runtimeType, props); - } else { - return '$runtimeType'; - } + return stringify ? mapPropsToString(runtimeType, props) : '$runtimeType'; } } diff --git a/lib/src/core/equality/deep_collection_equality.dart b/lib/src/core/equality/deep_collection_equality.dart new file mode 100644 index 000000000..b87508129 --- /dev/null +++ b/lib/src/core/equality/deep_collection_equality.dart @@ -0,0 +1,74 @@ +class DeepCollectionEquality { + const DeepCollectionEquality(); + bool equals(Object? obj1, Object? obj2) { + if (identical(obj1, obj2)) return true; + if (obj1.runtimeType != obj2.runtimeType) return false; + + if (obj1 is Map) { + return _mapsEqual(obj1, obj2 as Map); + } else if (obj1 is Set) { + return _setsEqual(obj1, obj2 as Set); + } else if (obj1 is Iterable) { + return _iterablesEqual(obj1, obj2 as Iterable); + } + + return obj1 == obj2; + } + + int hash(Object? obj) { + if (obj is Map) { + return Object.hashAllUnordered(obj.keys) ^ + Object.hashAllUnordered(obj.values); + } else if (obj is Set) { + return Object.hashAllUnordered(obj); + } else if (obj is Iterable) { + int hashCode = 0; + for (var value in obj) { + hashCode ^= hash(value); + } + + return hashCode; + } + + return obj.hashCode; + } + + bool _mapsEqual(Map map1, Map map2) { + if (map1.length != map2.length) return false; + for (var key in map1.keys) { + if (!map2.containsKey(key) || !equals(map1[key], map2[key])) { + return false; + } + } + + return true; + } + + bool _iterablesEqual(Iterable iter1, Iterable iter2) { + // Use hash values to compare iterables. + if (iter1.length != iter2.length) return false; + // Check if iterables are in order + if (iter1 is List && iter2 is List) { + for (int i = 0; i < iter1.length; i++) { + if (!equals(iter1[i], iter2[i])) { + return false; + } + } + + return true; + } + + return false; + } + + bool _setsEqual(Set set1, Set set2) { + if (set1.length != set2.length) return false; + for (var value in set1) { + if (!set2.contains(value)) { + return false; + } + } + + return true; + } +} diff --git a/lib/src/decorators/built_in_decorators/aspect_ratio.dart b/lib/src/decorators/built_in_decorators/aspect_ratio.dart deleted file mode 100644 index d06fc6ece..000000000 --- a/lib/src/decorators/built_in_decorators/aspect_ratio.dart +++ /dev/null @@ -1,50 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../../attributes/shared/shared.descriptor.dart'; -import '../../factory/mix_provider_data.dart'; -import '../decorator.dart'; - -class AspectRatioDecorator extends WidgetDecorator { - final double aspectRatio; - const AspectRatioDecorator({ - required this.aspectRatio, - super.key, - }); - - @override - AspectRatioDecorator merge(AspectRatioDecorator other) { - return AspectRatioDecorator( - aspectRatio: other.aspectRatio, - ); - } - - @override - Widget build(MixData mix, Widget child) { - final common = CommonDescriptor.fromContext(mix); - - if (common.animated) { - return TweenAnimationBuilder( - tween: Tween(end: aspectRatio), - duration: common.animationDuration, - curve: common.animationCurve, - builder: (context, value, child) { - return AspectRatio( - key: key, - aspectRatio: value, - child: child, - ); - }, - child: child, - ); - } else { - return AspectRatio( - key: key, - aspectRatio: aspectRatio, - child: child, - ); - } - } - - @override - get props => [aspectRatio]; -} diff --git a/lib/src/decorators/built_in_decorators/clip_decorator.dart b/lib/src/decorators/built_in_decorators/clip_decorator.dart deleted file mode 100644 index 580e9b73b..000000000 --- a/lib/src/decorators/built_in_decorators/clip_decorator.dart +++ /dev/null @@ -1,128 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../../attributes/shared/shared.descriptor.dart'; -import '../../factory/mix_provider_data.dart'; -import '../decorator.dart'; - -enum ClipDecoratorType { - triangle, - rect, - rounded, - oval, -} - -class ClipDecorator extends WidgetDecorator { - final BorderRadius borderRadius; - final ClipDecoratorType clipType; - - const ClipDecorator( - this.clipType, { - this.borderRadius = BorderRadius.zero, - super.key, - }); - - @override - ClipDecorator merge(ClipDecorator other) { - return other; - } - - @override - Widget build(MixData mix, Widget child) { - final common = CommonDescriptor.fromContext(mix); - - if (clipType == ClipDecoratorType.triangle) { - return ClipPath( - key: key, - clipper: TriangleClipper(), - child: child, - ); - } - - if (clipType == ClipDecoratorType.rect) { - return ClipRect( - key: key, - child: child, - ); - } - - if (clipType == ClipDecoratorType.rounded) { - if (common.animated) { - return AnimatedClipRRect( - key: key, - duration: common.animationDuration, - curve: common.animationCurve, - borderRadius: borderRadius, - child: child, - ); - } else { - return ClipRRect( - key: key, - borderRadius: borderRadius, - child: child, - ); - } - } - - if (clipType == ClipDecoratorType.oval) { - return ClipOval( - key: key, - child: child, - ); - } - - throw Exception('Unknown clip type: $clipType'); - } - - @override - get props => [borderRadius, clipType]; -} - -class AnimatedClipRRect extends StatelessWidget { - const AnimatedClipRRect({ - required this.duration, - this.curve = Curves.linear, - required this.borderRadius, - required this.child, - Key? key, - }) : super(key: key); - - final Duration duration; - final Curve curve; - final BorderRadius borderRadius; - final Widget child; - - static Widget _builder( - BuildContext context, - BorderRadius radius, - Widget? child, - ) { - return ClipRRect(borderRadius: radius, child: child); - } - - @override - Widget build(BuildContext context) { - return TweenAnimationBuilder( - duration: duration, - curve: curve, - tween: Tween(begin: BorderRadius.zero, end: borderRadius), - builder: _builder, - child: child, - ); - } -} - -class TriangleClipper extends CustomClipper { - @override - Path getClip(Size size) { - final path = Path(); - path.moveTo(size.width / 2, 0.0); - path.lineTo(size.width, size.height); - path.lineTo(0.0, size.height); - path.close(); - - return path; - } - - @override - bool shouldReclip(TriangleClipper oldClipper) => false; -} diff --git a/lib/src/decorators/built_in_decorators/flexible.dart b/lib/src/decorators/built_in_decorators/flexible.dart deleted file mode 100644 index 0e397ee55..000000000 --- a/lib/src/decorators/built_in_decorators/flexible.dart +++ /dev/null @@ -1,35 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../../factory/mix_provider_data.dart'; -import '../decorator.dart'; - -class FlexibleDecorator extends WidgetDecorator { - final FlexFit? flexFit; - final int? flex; - const FlexibleDecorator({ - this.flexFit, - this.flex, - super.key, - }); - - @override - FlexibleDecorator merge(FlexibleDecorator other) { - return FlexibleDecorator( - flexFit: other.flexFit ?? flexFit, - flex: other.flex ?? flex, - ); - } - - @override - Widget build(MixData mix, Widget child) { - return Flexible( - key: key, - fit: flexFit ?? FlexFit.loose, - flex: flex ?? 1, - child: child, - ); - } - - @override - get props => [flexFit, flex]; -} diff --git a/lib/src/decorators/built_in_decorators/opacity.dart b/lib/src/decorators/built_in_decorators/opacity.dart deleted file mode 100644 index 61e323f49..000000000 --- a/lib/src/decorators/built_in_decorators/opacity.dart +++ /dev/null @@ -1,42 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../../attributes/shared/shared.descriptor.dart'; -import '../../factory/mix_provider_data.dart'; -import '../decorator.dart'; - -class OpacityDecorator extends WidgetDecorator { - final double opacity; - const OpacityDecorator({ - required this.opacity, - super.key, - }); - - @override - OpacityDecorator merge(OpacityDecorator other) { - return OpacityDecorator(opacity: other.opacity); - } - - @override - Widget build(MixData mix, Widget child) { - final common = CommonDescriptor.fromContext(mix); - - if (common.animated) { - return AnimatedOpacity( - key: key, - duration: common.animationDuration, - curve: common.animationCurve, - opacity: opacity, - child: child, - ); - } else { - return Opacity( - key: key, - opacity: opacity, - child: child, - ); - } - } - - @override - get props => [opacity]; -} diff --git a/lib/src/decorators/built_in_decorators/rotate.dart b/lib/src/decorators/built_in_decorators/rotate.dart deleted file mode 100644 index ede930e98..000000000 --- a/lib/src/decorators/built_in_decorators/rotate.dart +++ /dev/null @@ -1,44 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../../attributes/shared/shared.descriptor.dart'; -import '../../factory/mix_provider_data.dart'; -import '../decorator.dart'; - -class RotateDecorator extends WidgetDecorator { - final int quarterTurns; - const RotateDecorator({ - required this.quarterTurns, - super.key, - }); - - @override - RotateDecorator merge(RotateDecorator other) { - return RotateDecorator( - quarterTurns: other.quarterTurns, - ); - } - - @override - Widget build(MixData mix, Widget child) { - final common = CommonDescriptor.fromContext(mix); - - if (common.animated) { - return AnimatedRotation( - key: key, - duration: common.animationDuration, - curve: common.animationCurve, - turns: quarterTurns / 4, - child: child, - ); - } - - return RotatedBox( - key: key, - quarterTurns: quarterTurns, - child: child, - ); - } - - @override - get props => [quarterTurns]; -} diff --git a/lib/src/decorators/built_in_decorators/scale.dart b/lib/src/decorators/built_in_decorators/scale.dart deleted file mode 100644 index 8b046d3ed..000000000 --- a/lib/src/decorators/built_in_decorators/scale.dart +++ /dev/null @@ -1,47 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../../attributes/shared/shared.descriptor.dart'; -import '../../factory/mix_provider_data.dart'; -import '../decorator.dart'; - -class ScaleDecorator extends WidgetDecorator { - final double scale; - const ScaleDecorator( - this.scale, { - super.key, - }); - - @override - ScaleDecorator merge(ScaleDecorator other) { - return ScaleDecorator(other.scale); - } - - @override - Widget build(MixData mix, Widget child) { - final common = CommonDescriptor.fromContext(mix); - if (common.animated) { - return TweenAnimationBuilder( - tween: Tween(begin: 1, end: scale), - duration: common.animationDuration, - curve: common.animationCurve, - builder: (context, value, child) { - return Transform.scale( - key: key, - scale: value, - child: child, - ); - }, - child: child, - ); - } else { - return Transform.scale( - key: key, - scale: scale, - child: child, - ); - } - } - - @override - get props => [scale]; -} diff --git a/lib/src/decorators/clip_decorator.dart b/lib/src/decorators/clip_decorator.dart new file mode 100644 index 000000000..8483d61e1 --- /dev/null +++ b/lib/src/decorators/clip_decorator.dart @@ -0,0 +1,266 @@ +import 'package:flutter/material.dart'; + +import '../attributes/attribute.dart'; +import '../factory/mix_provider_data.dart'; +import 'decorator.dart'; + +abstract class ClipDecorator extends ParentDecorator> { + final CustomClipper? clipper; + final Clip? clipBehavior; + + const ClipDecorator({this.clipper, this.clipBehavior}); + + @override + ClipDecorator merge(covariant ClipDecorator other); + + @override + ClipDecoratorData resolve(MixData mix); + + @override + get props => [clipper, clipBehavior]; + + @override + Widget build(Widget child, covariant ClipDecoratorData data); +} + +class ClipDecoratorData extends MixExtension> { + final Clip? clipBehavior; + final CustomClipper? clipper; + + const ClipDecoratorData({this.clipper, this.clipBehavior}); + + @override + ClipDecoratorData lerp(ClipDecoratorData other, double t) { + return ClipDecoratorData( + clipper: snap(clipper, other.clipper, t), + clipBehavior: snap(clipBehavior, other.clipBehavior, t), + ); + } + + @override + ClipDecoratorData copyWith({ + Clip? clipBehavior, + CustomClipper? clipper, + }) { + return ClipDecoratorData( + clipper: clipper ?? this.clipper, + clipBehavior: clipBehavior ?? this.clipBehavior, + ); + } + + @override + get props => [clipper, clipBehavior]; +} + +class ClipOvalDecorator extends ClipDecorator { + const ClipOvalDecorator({super.clipper, super.clipBehavior}); + + @override + ClipOvalDecorator merge(ClipOvalDecorator other) { + return ClipOvalDecorator( + clipper: other.clipper ?? clipper, + clipBehavior: other.clipBehavior ?? clipBehavior, + ); + } + + @override + ClipDecoratorData resolve(MixData mix) { + return ClipDecoratorData(clipper: clipper, clipBehavior: clipBehavior); + } + + @override + Widget build(Widget child, ClipDecoratorData data) { + return ClipOval( + clipper: data.clipper, + clipBehavior: data.clipBehavior ?? Clip.antiAlias, + child: child, + ); + } +} + +class ClipPathDecorator extends ClipDecorator { + const ClipPathDecorator({super.clipper, super.clipBehavior}); + + @override + ClipPathDecorator merge(ClipPathDecorator other) { + return ClipPathDecorator( + clipper: other.clipper, + clipBehavior: other.clipBehavior ?? clipBehavior, + ); + } + + @override + ClipDecoratorData resolve(MixData mix) { + return ClipDecoratorData( + clipper: clipper, + clipBehavior: clipBehavior ?? Clip.antiAlias, + ); + } + + @override + Widget build(Widget child, ClipDecoratorData data) { + return ClipPath( + clipper: data.clipper, + clipBehavior: data.clipBehavior ?? Clip.antiAlias, + child: child, + ); + } +} + +class ClipRRectDecoratorData extends ClipDecoratorData { + final BorderRadius? borderRadius; + + const ClipRRectDecoratorData({ + required this.borderRadius, + super.clipBehavior, + super.clipper, + }); + + @override + ClipRRectDecoratorData lerp(ClipRRectDecoratorData other, double t) { + return ClipRRectDecoratorData( + borderRadius: BorderRadius.lerp(borderRadius, other.borderRadius, t), + clipBehavior: snap(clipBehavior, other.clipBehavior, t), + clipper: snap(clipper, other.clipper, t), + ); + } + + @override + ClipRRectDecoratorData copyWith({ + BorderRadius? borderRadius, + Clip? clipBehavior, + CustomClipper? clipper, + }) { + return ClipRRectDecoratorData( + borderRadius: borderRadius ?? this.borderRadius, + clipBehavior: clipBehavior ?? this.clipBehavior, + clipper: clipper ?? this.clipper, + ); + } + + @override + get props => [borderRadius, clipper, clipBehavior]; +} + +class ClipRectDecorator extends ClipDecorator { + const ClipRectDecorator({super.clipper, super.clipBehavior}); + + @override + ClipRectDecorator merge(ClipRectDecorator other) { + return ClipRectDecorator( + clipper: other.clipper, + clipBehavior: other.clipBehavior ?? clipBehavior, + ); + } + + @override + ClipDecoratorData resolve(MixData mix) { + return ClipDecoratorData( + clipper: clipper, + clipBehavior: clipBehavior ?? Clip.hardEdge, + ); + } + + @override + get props => [clipper, clipBehavior]; + + @override + Widget build(Widget child, ClipDecoratorData data) { + return ClipRect( + clipper: data.clipper, + clipBehavior: data.clipBehavior ?? Clip.hardEdge, + child: child, + ); + } +} + +class ClipRRectDecorator extends ClipDecorator { + final BorderRadius? borderRadius; + const ClipRRectDecorator({ + super.clipper, + super.clipBehavior, + this.borderRadius, + }); + + @override + ClipRRectDecorator merge(ClipRRectDecorator other) { + return ClipRRectDecorator( + clipper: other.clipper, + clipBehavior: other.clipBehavior ?? clipBehavior, + borderRadius: other.borderRadius ?? borderRadius, + ); + } + + @override + ClipRRectDecoratorData resolve(MixData mix) { + return ClipRRectDecoratorData( + borderRadius: borderRadius ?? BorderRadius.zero, + clipBehavior: clipBehavior ?? Clip.antiAlias, + clipper: clipper, + ); + } + + @override + get props => [clipper, clipBehavior, borderRadius]; + + @override + Widget build(Widget child, ClipRRectDecoratorData data) { + return ClipRRect( + borderRadius: data.borderRadius ?? BorderRadius.zero, + clipper: data.clipper, + clipBehavior: data.clipBehavior ?? Clip.antiAlias, + child: child, + ); + } +} + +class AnimatedClipRRect extends StatelessWidget { + const AnimatedClipRRect({ + required this.duration, + this.curve = Curves.linear, + required this.borderRadius, + required this.child, + Key? key, + }) : super(key: key); + + static Widget _builder( + BuildContext context, + BorderRadius radius, + Widget? child, + ) { + return ClipRRect(borderRadius: radius, child: child); + } + + final Duration duration; + final Curve curve; + final BorderRadius borderRadius; + final Widget child; + + @override + Widget build(BuildContext context) { + return TweenAnimationBuilder( + tween: Tween(begin: BorderRadius.zero, end: borderRadius), + duration: duration, + curve: curve, + builder: _builder, + child: child, + ); + } +} + +class TriangleClipper extends CustomClipper { + const TriangleClipper(); + @override + Path getClip(Size size) { + final path = Path(); + path.moveTo(size.width / 2, 0.0); + path.lineTo(size.width, size.height); + path.lineTo(0.0, size.height); + path.close(); + + return path; + } + + @override + bool shouldReclip(TriangleClipper oldClipper) => false; +} diff --git a/lib/src/decorators/decorator.dart b/lib/src/decorators/decorator.dart index 05997b348..89f7833b4 100644 --- a/lib/src/decorators/decorator.dart +++ b/lib/src/decorators/decorator.dart @@ -1,41 +1,27 @@ import 'package:flutter/material.dart'; -import '../../mix.dart'; +import '../attributes/attribute.dart'; +import '../factory/mix_provider_data.dart'; -abstract class Decorator> extends StyleAttribute - with Mergeable> { - const Decorator({ - this.key, - }); +abstract class Decorator extends VisualAttribute { + const Decorator(); - /// Key is required in order for proper sorting - final Key? key; - - Widget build(MixData mix, Widget child); + Widget render(Widget child, MixData mix) { + return build(child, resolve(mix)); + } @override - Decorator merge(covariant Decorator other); + Decorator merge(covariant Decorator? other); - Widget render(MixData mix, Widget child) { - return build(mix, child); - } + Widget build(Widget child, T data); } -abstract class WidgetDecorator> - extends StyleAttribute with Mergeable> { - const WidgetDecorator({ - this.key, - }); - - /// Key is required in order for proper sorting - final Key? key; - - Widget build(MixData mix, Widget child); +abstract class ParentDecorator extends Decorator { + const ParentDecorator(); @override - WidgetDecorator merge(covariant WidgetDecorator other); + ParentDecorator merge(covariant ParentDecorator? other); - Widget render(MixData mix, Widget child) { - return build(mix, child); - } + @override + Widget build(Widget child, T data); } diff --git a/lib/src/decorators/decorators_utilities.dart b/lib/src/decorators/decorators_utilities.dart deleted file mode 100644 index 7609d41b9..000000000 --- a/lib/src/decorators/decorators_utilities.dart +++ /dev/null @@ -1,56 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../../mix.dart'; - -class DecoratorUtility { - static FlexibleDecorator flex(int value) { - return FlexibleDecorator(flex: value); - } - - static FlexibleDecorator flexFit(FlexFit flexFit) { - return FlexibleDecorator(flexFit: flexFit); - } - - static FlexibleDecorator expanded() { - return const FlexibleDecorator(flexFit: FlexFit.tight); - } - - static FlexibleDecorator flexible() { - return const FlexibleDecorator(flexFit: FlexFit.loose); - } - - static AspectRatioDecorator aspectRatio(double aspectRatio) { - return AspectRatioDecorator(aspectRatio: aspectRatio); - } - - static ClipDecorator clipRounded(double radius) { - return ClipDecorator( - ClipDecoratorType.rounded, - borderRadius: BorderRadius.circular(radius), - ); - } - - static ScaleDecorator scale(double scale) { - return ScaleDecorator(scale); - } - - static ClipDecorator clipOval() { - return const ClipDecorator(ClipDecoratorType.oval); - } - - static ClipDecorator clipTriangle() { - return const ClipDecorator(ClipDecoratorType.triangle); - } - - static OpacityDecorator opacity(double opacity) { - return OpacityDecorator(opacity: opacity); - } - - static RotateDecorator rotate(int quarterTurns) { - return RotateDecorator(quarterTurns: quarterTurns); - } - - static RotateDecorator rotate90() => rotate(1); - static RotateDecorator rotate180() => rotate(2); - static RotateDecorator rotate270() => rotate(3); -} diff --git a/lib/src/decorators/default_decorators.dart b/lib/src/decorators/default_decorators.dart new file mode 100644 index 000000000..cd2a12121 --- /dev/null +++ b/lib/src/decorators/default_decorators.dart @@ -0,0 +1,121 @@ +import 'package:flutter/material.dart'; + +import '../factory/mix_provider_data.dart'; +import 'decorator.dart'; + +class AspectRatioDecorator extends ParentDecorator { + final double aspectRatio; + const AspectRatioDecorator(this.aspectRatio); + + @override + AspectRatioDecorator merge(AspectRatioDecorator other) { + return AspectRatioDecorator(other.aspectRatio); + } + + @override + double resolve(MixData mix) => aspectRatio; + + @override + get props => [aspectRatio]; + + @override + Widget build(Widget child, double data) => + AspectRatio(aspectRatio: data, child: child); +} + +class FlexibleDecorator extends ParentDecorator { + final int? flex; + final FlexFit? flexFit; + const FlexibleDecorator({this.flex, this.flexFit}); + + const FlexibleDecorator.tight([this.flex]) : flexFit = FlexFit.tight; + const FlexibleDecorator.loose([this.flex]) : flexFit = FlexFit.loose; + + @override + FlexibleDecorator merge(FlexibleDecorator other) { + return FlexibleDecorator( + flex: other.flex ?? flex, + flexFit: other.flexFit ?? flexFit, + ); + } + + @override + FlexibleDecoratorSpec resolve(MixData mix) { + return FlexibleDecoratorSpec(flex: flex, flexFit: flexFit); + } + + @override + get props => [flexFit, flex]; + + @override + Widget build(child, data) { + return Flexible( + flex: data.flex ?? 1, + fit: data.flexFit ?? FlexFit.loose, + child: child, + ); + } +} + +class FlexibleDecoratorSpec { + final int? flex; + final FlexFit? flexFit; + const FlexibleDecoratorSpec({required this.flex, required this.flexFit}); +} + +class OpacityDecorator extends ParentDecorator { + final double value; + const OpacityDecorator(this.value); + + @override + OpacityDecorator merge(OpacityDecorator? other) { + return OpacityDecorator(other?.value ?? value); + } + + @override + double resolve(MixData mix) => value; + + @override + get props => [value]; + + @override + Widget build(child, data) => Opacity(opacity: data, child: child); +} + +class RotateDecorator extends ParentDecorator { + final int value; + const RotateDecorator(this.value); + + @override + RotateDecorator merge(RotateDecorator other) { + return RotateDecorator(other.value); + } + + @override + int resolve(MixData mix) => value; + + @override + get props => [value]; + + @override + Widget build(child, data) => RotatedBox(quarterTurns: data, child: child); +} + +class ScaleDecorator extends ParentDecorator { + final double scale; + const ScaleDecorator(this.scale); + + @override + ScaleDecorator merge(ScaleDecorator? other) { + return ScaleDecorator(other?.scale ?? scale); + } + + @override + double resolve(MixData mix) => scale; + + @override + get props => [scale]; + + @override + Widget build(child, data) => Transform.scale(scale: data, child: child); +} diff --git a/lib/src/decorators/exports.dart b/lib/src/decorators/exports.dart deleted file mode 100644 index c45e7b991..000000000 --- a/lib/src/decorators/exports.dart +++ /dev/null @@ -1,6 +0,0 @@ -export 'built_in_decorators/aspect_ratio.dart'; -export 'built_in_decorators/clip_decorator.dart'; -export 'built_in_decorators/flexible.dart'; -export 'built_in_decorators/opacity.dart'; -export 'built_in_decorators/rotate.dart'; -export 'built_in_decorators/scale.dart'; diff --git a/lib/src/decorators/widget_decorator_wrapper.dart b/lib/src/decorators/widget_decorator_wrapper.dart index 06e0ac910..57de000e0 100644 --- a/lib/src/decorators/widget_decorator_wrapper.dart +++ b/lib/src/decorators/widget_decorator_wrapper.dart @@ -1,14 +1,9 @@ import 'package:flutter/material.dart'; import '../factory/mix_provider_data.dart'; -import 'decorator.dart'; class WidgetDecoratorWrapper extends StatelessWidget { - const WidgetDecoratorWrapper( - this.mix, { - super.key, - required this.child, - }); + const WidgetDecoratorWrapper(this.mix, {required this.child, super.key}); final MixData mix; @@ -16,40 +11,14 @@ class WidgetDecoratorWrapper extends StatelessWidget { @override Widget build(BuildContext context) { - var current = child; - - if (mix.decorators?.isNotEmpty == true) { - for (var decorator in mix.decorators!) { - current = _RenderDecoratorWidget( - decorator, - mix: mix, - key: decorator.key, - child: current, - ); - } - } + Widget current = child; + // TODO: review the use of key for re-render + // if (mix.decorators.isNotEmpty) { + // for (final decorator in mix.decorators) { + // current = decorator.build(current, mix); + // } + // } return current; } } - -class _RenderDecoratorWidget extends StatelessWidget { - const _RenderDecoratorWidget( - this.decorator, { - required this.mix, - super.key, - required this.child, - }); - - final WidgetDecorator decorator; - final MixData mix; - final Widget child; - - @override - Widget build(BuildContext context) { - return decorator.render( - mix, - child, - ); - } -} diff --git a/lib/src/deprecations.dart b/lib/src/deprecations.dart new file mode 100644 index 000000000..c4cdd88ba --- /dev/null +++ b/lib/src/deprecations.dart @@ -0,0 +1,504 @@ +import 'dart:ui'; + +import 'package:flutter/material.dart'; + +import 'attributes/alignment_attribute.dart'; +import 'attributes/attribute.dart'; +import 'attributes/border/border_radius_attribute.dart'; +import 'attributes/scalar_attribute.dart'; +import 'attributes/style_mix_attribute.dart'; +import 'attributes/text_style_attribute.dart'; +import 'core/constants.dart'; +import 'directives/text_directive.dart'; +import 'factory/mix_provider_data.dart'; +import 'factory/style_mix.dart'; +import 'helpers/extensions/values_ext.dart'; +import 'theme/tokens/space_token.dart'; +import 'utils/alignment_util.dart'; +import 'utils/border_radius_util.dart'; +import 'utils/border_util.dart'; +import 'utils/box_constraints_util.dart'; +import 'utils/context_variant_util.dart'; +import 'utils/decoration_util.dart'; +import 'utils/decorators_util.dart'; +import 'utils/helper_util.dart'; +import 'utils/pressable_util.dart'; +import 'utils/scalar_util.dart'; +import 'utils/space_util.dart'; +import 'utils/text_util.dart'; +import 'variants/variant.dart'; + +extension DeprecatedMixExtension on StyleMix { + /// Adds an Attribute to a Mix. + @Deprecated('Simplifying the mix API to avoid confusion. Use apply instead') + SpreadFunctionParams get mix { + return SpreadFunctionParams(addAttributes); + } + + @Deprecated('Use selectVariants now') + StyleMix withVariants(List variants) { + return withManyVariants(variants); + } + + @Deprecated( + 'Use merge() or mergeMany() now. You might have to turn into a Mix first. firstMixFactory.merge(secondMix)', + ) + StyleMix addAttributes(Iterable attributes) { + return merge(StyleMix.create(attributes)); + } + + @Deprecated('Use selectVariants now') + StyleMix withManyVariants(Iterable variants) { + return selectVariantList(variants); + } + + @Deprecated('Use merge() or mergeMany() instead') + SpreadFunctionParams get apply => + const SpreadFunctionParams(StyleMix.combineList); + + @Deprecated('Use selectVariant now') + StyleMix withVariant(Variant variant) { + return selectVariant(variant); + } + + @Deprecated('Use combine now') + StyleMix combineAll(List mixes) { + return StyleMix.combineList(mixes); + } + + @Deprecated('Use selectVariant now') + StyleMix withMaybeVariant(Variant? variant) { + if (variant == null) return this; + + return withVariant(variant); + } + + @Deprecated('Use mergeNullable instead') + StyleMix maybeApply(StyleMix? mix) { + if (mix == null) return this; + + return apply(mix); + } + + @Deprecated('Use applyNullable instead') + StyleMix applyMaybe(StyleMix? mix) { + return maybeApply(mix); + } +} + +/// This refers to the deprecated class MixData and it's here for the purpose of maintaining compatibility. +@Deprecated('Use MixData instead.') +typedef MixContext = MixData; + +extension WithSpaceTokensExt on UtilityWithSpaceTokens { + @Deprecated('Use xsmall instead') + T get xs => this.xsmall; + @Deprecated('Use small instead') + T get sm => this.small; + @Deprecated('Use medium instead') + T get md => this.medium; + @Deprecated('Use large instead') + T get lg => this.large; + @Deprecated('Use xlarge instead') + T get xl => xlarge; + @Deprecated('Use xxlarge instead') + T get xxl => xxlarge; +} + +@Deprecated('Use mainAxisAlignment instead') +const mainAxis = mainAxisAlignment; + +@Deprecated('Use onXSmall instead') +final xsmall = onXSmall; + +@Deprecated('Use onSmall instead') +final small = onSmall; + +@Deprecated('Use onMedium instead') +final medium = onMedium; + +@Deprecated('Use onDark instead') +final dark = onDark; + +@Deprecated('Use onLight instead') +final light = onLight; + +@Deprecated('Use onLarge instead') +final large = onLarge; + +@Deprecated('Use onHover instead') +final hover = onHover; + +@Deprecated('Use onFocus instead') +final focus = onFocus; + +@Deprecated('Use onPortrait instead') +final portrait = onPortrait; + +@Deprecated('Use onLandscape instead') +final landscape = onLandscape; + +@Deprecated('Use onDisabled instead') +final disabled = onDisabled; + +@Deprecated('Use onEnabled instead') +final enabled = onEnabled; + +@Deprecated('Use onPress instead') +final press = onPress; + +@Deprecated('Use onNot instead') +const not = onNot; + +@Deprecated('Use textStyle instead') +const font = textStyle; + +@Deprecated('Use textStyle(textShadow: textShadow) instead') +TextStyleAttribute textShadow(List textShadow) { + return textStyle(shadows: textShadow); +} + +@Deprecated('Use flexible or expanded') +const flex = flexible; + +@Deprecated('Use textStyle(textShadow: textShadow) instead') +const fontWeight = LegacyTextStyleUtility.fontWeight; + +@Deprecated('Use textStyle(letterSpacing: letterSpacing) instead') +const letterSpacing = LegacyTextStyleUtility.letterSpacing; + +@Deprecated('Use textStyle(debugLabel: debugLabel) instead') +const debugLabel = LegacyTextStyleUtility.debugLabel; + +@Deprecated('Use textStyle(height: height) instead') +const textHeight = LegacyTextStyleUtility.textHeight; + +@Deprecated('Use textStyle(wordSpacing: wordSpacing) instead') +const wordSpacing = LegacyTextStyleUtility.wordSpacing; + +@Deprecated('Use textStyle(fontStyle: fontStyle) instead') +const fontStyle = LegacyTextStyleUtility.fontStyle; + +@Deprecated('Use textStyle(fontSize: fontSize) instead') +const fontSize = LegacyTextStyleUtility.fontSize; + +@Deprecated('Use textStyle(inherit: inherit) instead') +const inherit = LegacyTextStyleUtility.inherit; + +@Deprecated('Use textStyle(color: color) instead') +const textColor = LegacyTextStyleUtility.textColor; + +@Deprecated('Use textStyle(backgroundColor: backgroundColor) instead') +const textBgColor = LegacyTextStyleUtility.textBgColor; + +@Deprecated('Use textStyle(foreground: foreground) instead') +const textForeground = LegacyTextStyleUtility.textForeground; + +@Deprecated('Use textStyle(background: background) instead') +const textBackground = LegacyTextStyleUtility.textBackground; + +@Deprecated('Use textStyle(shadows: shadows) instead') +const textShadows = LegacyTextStyleUtility.textShadow; + +@Deprecated('Use textStyle(fontFeatures: fontFeatures) instead') +const fontFeatures = LegacyTextStyleUtility.fontFeatures; + +@Deprecated('Use textStyle(decoration: decoration) instead') +const textDecoration = LegacyTextStyleUtility.textDecoration; + +@Deprecated('Use textStyle(decorationColor: decorationColor) instead') +const textDecorationColor = LegacyTextStyleUtility.textDecorationColor; + +@Deprecated('Use textStyle(decorationStyle: decorationStyle) instead') +const textDecorationStyle = LegacyTextStyleUtility.textDecorationStyle; + +@Deprecated('Use textStyle(decorationThickness: decorationThickness) instead') +const textDecorationThickness = LegacyTextStyleUtility.textDecorationThickness; + +@Deprecated('Use textStyle(fontFamilyFallback: fontFamilyFallback) instead') +const fontFamilyFallback = LegacyTextStyleUtility.fontFamilyFallback; + +class LegacyTextStyleUtility { + static TextStyle textShadow(List shadows) { + return TextStyle(shadows: shadows); + } + + static TextStyle fontWeight(FontWeight weight) { + return TextStyle(fontWeight: weight); + } + + static TextStyle textBaseline(TextBaseline baseline) { + return TextStyle(textBaseline: baseline); + } + + static TextStyle letterSpacing(double spacing) { + return TextStyle(letterSpacing: spacing); + } + + static TextStyle debugLabel(String label) { + return TextStyle(debugLabel: label); + } + + static TextStyle textHeight(double height) { + return TextStyle(height: height); + } + + static TextStyle wordSpacing(double spacing) { + return TextStyle(wordSpacing: spacing); + } + + static TextStyle fontStyle(FontStyle style) { + return TextStyle(fontStyle: style); + } + + static TextStyle fontSize(double size) { + return TextStyle(fontSize: size); + } + + static TextStyle inherit(bool value) { + return TextStyle(inherit: value); + } + + static TextStyle textColor(Color color) { + return TextStyle(color: color); + } + + static TextStyle textBgColor(Color backgroundColor) { + return TextStyle(backgroundColor: backgroundColor); + } + + static TextStyle textForeground(Paint foreground) { + return TextStyle(foreground: foreground); + } + + static TextStyle textBackground(Paint background) { + return TextStyle(background: background); + } + + static TextStyle fontFeatures(List features) { + return TextStyle(fontFeatures: features); + } + + static TextStyle textDecoration(TextDecoration decoration) { + return TextStyle(decoration: decoration); + } + + static TextStyle textDecorationColor(Color decorationColor) { + return TextStyle(decorationColor: decorationColor); + } + + static TextStyle textDecorationStyle(TextDecorationStyle decorationStyle) { + return TextStyle(decorationStyle: decorationStyle); + } + + static TextStyle textDecorationThickness(double decorationThickness) { + return TextStyle(decorationThickness: decorationThickness); + } + + static TextStyle fontFamilyFallback(List fontFamilyFallback) { + return TextStyle(fontFamilyFallback: fontFamilyFallback); + } +} + +@Deprecated('Use style.merge(otherStyle), instead') +const apply = SpreadFunctionParams(_apply); + +StyleMixAttribute _apply(Iterable mixes) { + return StyleMixAttribute(StyleMix.combineList(mixes)); +} + +@Deprecated(kShortAliasDeprecation) +final p = padding; + +@Deprecated(kShortAliasDeprecation) +final pt = paddingTop; + +@Deprecated(kShortAliasDeprecation) +final pb = paddingBottom; + +@Deprecated(kShortAliasDeprecation) +final pr = paddingRight; + +@Deprecated(kShortAliasDeprecation) +final pl = paddingLeft; + +@Deprecated(kShortAliasDeprecation) +final ps = paddingStart; + +@Deprecated(kShortAliasDeprecation) +final pe = paddingEnd; + +@Deprecated(kShortAliasDeprecation) +final px = paddingHorizontal; + +@Deprecated(kShortAliasDeprecation) +final py = paddingVertical; + +@Deprecated(kShortAliasDeprecation) +const pi = paddingFrom; + +@Deprecated(kShortAliasDeprecation) +final m = margin; +@Deprecated(kShortAliasDeprecation) +final mt = marginTop; +@Deprecated(kShortAliasDeprecation) +final mb = marginBottom; +@Deprecated(kShortAliasDeprecation) +final mr = marginRight; +@Deprecated(kShortAliasDeprecation) +final ml = marginLeft; +@Deprecated(kShortAliasDeprecation) +final ms = marginStart; +@Deprecated(kShortAliasDeprecation) +final me = marginEnd; +@Deprecated(kShortAliasDeprecation) +final mx = marginHorizontal; +@Deprecated(kShortAliasDeprecation) +final my = marginVertical; +@Deprecated(kShortAliasDeprecation) +const mi = marginFrom; + +@Deprecated(kShortAliasDeprecation) +final marginX = marginHorizontal; + +@Deprecated(kShortAliasDeprecation) +final marginY = marginVertical; + +@Deprecated(kShortAliasDeprecation) +const r = rounded; + +@Deprecated(kShortAliasDeprecation) +const roundedH = roundedHorizontal; + +@Deprecated(kShortAliasDeprecation) +const roundedV = roundedVertical; + +@Deprecated(kShortAliasDeprecation) +dynamic get roundedDH => UnimplementedError(); + +@Deprecated(kShortAliasDeprecation) +const roundedTL = roundedTopLeft; + +@Deprecated(kShortAliasDeprecation) +BorderRadiusGeometryAttribute roundedTR() { + throw UnimplementedError(); +} + +@Deprecated(kShortAliasDeprecation) +BorderRadiusAttribute roundedBL() { + throw UnimplementedError(); +} + +@Deprecated(kShortAliasDeprecation) +BorderRadiusAttribute roundedBR() { + throw UnimplementedError(); +} + +@Deprecated(kShortAliasDeprecation) +BorderRadiusDirectionalAttribute roundedTS() { + throw UnimplementedError(); +} + +@Deprecated(kShortAliasDeprecation) +BorderRadiusDirectionalAttribute roundedTE() { + throw UnimplementedError(); +} + +@Deprecated(kShortAliasDeprecation) +BorderRadiusDirectionalAttribute roundedBS() { + throw UnimplementedError(); +} + +@Deprecated(kShortAliasDeprecation) +BorderRadiusDirectionalAttribute roundedBE() { + throw UnimplementedError(); +} + +@Deprecated(kShortAliasDeprecation) +const bgColor = backgroundColor; + +@Deprecated(kShortAliasDeprecation) +const h = height; + +@Deprecated(kShortAliasDeprecation) +const w = width; + +@Deprecated(kShortAliasDeprecation) +const maxH = maxHeight; + +@Deprecated(kShortAliasDeprecation) +const maxW = maxWidth; + +@Deprecated(kShortAliasDeprecation) +const minH = minHeight; + +@Deprecated(kShortAliasDeprecation) +const minW = minWidth; + +@Deprecated(kShortAliasDeprecation) +const bt = borderTop; + +@Deprecated(kShortAliasDeprecation) +const bb = borderBottom; + +@Deprecated(kShortAliasDeprecation) +const bl = borderLeft; + +@Deprecated(kShortAliasDeprecation) +const br = borderRight; + +@Deprecated(kShortAliasDeprecation) +const bs = borderStart; + +@Deprecated(kShortAliasDeprecation) +const be = borderEnd; + +@Deprecated('Use alignment instead') +const align = alignment; + +@Deprecated('Use stack instead') +AlignmentGeometryAttribute zAligmnent(Alignment alignment) { + return alignment.toAttribute(); +} + +@Deprecated('Use stackFit instead') +StackFitAttribute zFit(StackFit fit) { + return stackFit(fit); +} + +@Deprecated('Use stack instead') +ClipAttribute zClip(Clip clip) { + return ClipAttribute(clip); +} + +// Create a FlexAttributes for the direction axis. +@Deprecated('Use axis() instead') +AxisAttribute direction(Axis direction) { + return AxisAttribute(direction); +} + +// Create a FlexAttributes for the cross axis. +@Deprecated('Use crossAxisAlignment() instead') +CrossAxisAlignmentAttribute crossAxis(CrossAxisAlignment crossAxisAlignment) { + return CrossAxisAlignmentAttribute(crossAxisAlignment); +} + +@Deprecated('Use textDirective(directive)') +TextDirectiveAttribute directives(List directives) { + return TextDirectiveAttribute(directives); +} + +@Deprecated('Use textDirective(directive)') +TextDirectiveAttribute directive(TextDirective directive) { + return TextDirectiveAttribute([directive]); +} + +@Deprecated('Locale is now passed to StyledText widget') +TextStyleAttribute locale() { + throw UnimplementedError(); +} + +@Deprecated('Use text(overflow: overflow)') +TextOverflowAttribute overflow(TextOverflow overflow) { + return TextOverflowAttribute(overflow); +} diff --git a/lib/src/directives/color_dto_directives.dart b/lib/src/directives/color_dto_directives.dart deleted file mode 100644 index 4a1ee4684..000000000 --- a/lib/src/directives/color_dto_directives.dart +++ /dev/null @@ -1,5 +0,0 @@ -import 'package:flutter/material.dart'; - -Color contrastColor(Color color) { - return color.computeLuminance() > 0.5 ? Colors.black : Colors.white; -} diff --git a/lib/src/directives/directive_attribute.dart b/lib/src/directives/directive_attribute.dart index b0d4d0431..ba6b27582 100644 --- a/lib/src/directives/directive_attribute.dart +++ b/lib/src/directives/directive_attribute.dart @@ -1,4 +1,6 @@ -abstract class Directive { +import '../core/equality/compare_mixin.dart'; + +abstract class Directive with Comparable { const Directive(); T modify(covariant T value); } diff --git a/lib/src/directives/directives/controllers.dart b/lib/src/directives/directives/controllers.dart new file mode 100644 index 000000000..cb6e13e99 --- /dev/null +++ b/lib/src/directives/directives/controllers.dart @@ -0,0 +1,107 @@ +// ignore_for_file: avoid-non-ascii-symbols + +import 'dart:math'; + +import 'package:flutter/scheduler.dart'; + +// Class responsible for representing the state of a single character transition. +class Character { + final String from; + final String to; + final int start; + final int end; + String char = ''; + + // Initializes a new instance of the [Character] class. + // [from] is the initial character. + // [to] is the character that we want to transition to. + // [start] and [end] represent the frame range for the transition. + Character(this.from, this.to, this.end, this.start); +} + +/// [TextDecodingController] is a controller that manages the process of text decoding animation +/// +/// by providing efficient and Flutter-friendly state management for the animation states. +class TextDecodingController { + final Function(String value) _fn; + // The current state of the decoding process. + String _data = ''; + // Current frame of the decoding process. + int _frame = 0; + // Set of possible characters used during transition. + final _chars = '!<>-_\\/[]{}—=+*^?#________'; + // Queue to hold the Characters during the transition. + final _queue = []; + // Random instance for generating random start and end points. + final _random = Random(); + // Ticker used for advancing frames. + Ticker? _ticker; + + // Constructor for the [TextDecodingController] class. + TextDecodingController(Function(String value) fn) : _fn = fn; + + /// Updates the data to be decoded in animation. + /// + /// The given string [newText] is the target result of the animation and signifies the end-state. + void setData(String newText) { + final length = max(_data.length, newText.length); + final oldText = _data.padRight(length); + newText = newText.padRight(length); + + // Clear previous queue and populate it with characters from the new string. + _queue.clear(); + for (int i = 0; i < length; i++) { + final from = oldText[i]; + final to = newText[i]; + final start = _random.nextInt(200); + final end = start + _random.nextInt(200); + _queue.add(Character(from, to, end, start)); + } + _startTicker(); + } + + /// Stops the animation and releases allocated ticker resources. + void dispose() { + _ticker?.stop(canceled: true); // Stop the ticker safely. + } + + /// Initializes the ticker that drives the animation. + void _startTicker() { + _ticker?.stop(canceled: true); + _ticker = Ticker(_update); // Start the Ticker with frame update function.. + _ticker?.start(); + } + + /// Frame update handler. Updates the state of characters during transition and applies them in order. + void _update(Duration elapsedTime) { + String output = ''; + int complete = 0; + + for (Character c in _queue) { + if (_frame >= c.end) { + complete++; + output += c.to; + } else if (_frame >= c.start) { + c.char = _randomChar(); + output += c.char; + } else { + output += c.from; + } + } + + _data = output; + _fn(_data); + + // Once all characters have transitioned, stop the ticker. + if (complete == _queue.length) { + _ticker?.stop(); + } else { + _frame++; // If not, move on to the next frame. + } + } + + /// Returns a random character from the pool of possible characters. + String _randomChar() { + return _chars[_random.nextInt(_chars.length)]; + } +} diff --git a/lib/src/directives/directives/counter.dart b/lib/src/directives/directives/counter.dart new file mode 100644 index 000000000..6d35a093e --- /dev/null +++ b/lib/src/directives/directives/counter.dart @@ -0,0 +1,115 @@ +import 'package:flutter/material.dart'; + +void main() { + runApp(const MyApp()); +} + +class MyApp extends StatelessWidget { + const MyApp({super.key}); + + @override + Widget build(BuildContext context) { + return const MaterialApp(home: NumberTickerExample()); + } +} + +class NumberTickerExample extends StatefulWidget { + const NumberTickerExample({super.key}); + + @override + _NumberTickerExampleState createState() => _NumberTickerExampleState(); +} + +class _NumberTickerExampleState extends State { + final _textController = TextEditingController(); + + double _value = 0; + + void _updateValue() { + final text = _textController.text; + if (text.isNotEmpty && double.tryParse(text) != null) { + setState(() { + _value = double.parse(text); + }); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Number Ticker Example')), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + TextField( + controller: _textController, + decoration: const InputDecoration(hintText: 'Enter a number'), + keyboardType: TextInputType.number, + ), + const SizedBox(height: 20), + AnimatedNumberTicker(value: _value), + ], + ), + ), + floatingActionButton: FloatingActionButton( + tooltip: 'Animate', + onPressed: _updateValue, + child: const Icon(Icons.play_arrow), + ), + ); + } +} + +class AnimatedNumberTicker extends StatefulWidget { + const AnimatedNumberTicker({super.key, required this.value}); + + final double value; + + @override + _AnimatedNumberTickerState createState() => _AnimatedNumberTickerState(); +} + +class _AnimatedNumberTickerState extends State + with SingleTickerProviderStateMixin { + late AnimationController _controller; + late Animation _animation; + + @override + void initState() { + super.initState(); + _controller = AnimationController( + duration: const Duration(milliseconds: 500), + vsync: this, + ); + _animation = + Tween(begin: 0, end: widget.value).animate(_controller); + } + + @override + void didUpdateWidget(AnimatedNumberTicker oldWidget) { + super.didUpdateWidget(oldWidget); + if (widget.value != oldWidget.value) { + _animation = Tween(begin: _animation.value, end: widget.value) + .animate(_controller) + ..addListener(() { + setState(() {}); + }); + _controller.forward(from: 0); + } + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Text( + _animation.value.toStringAsFixed(2), // Display only 2 decimal places + style: const TextStyle(fontSize: 40), + ); + } +} diff --git a/lib/src/directives/directives/glitch.dart b/lib/src/directives/directives/glitch.dart new file mode 100644 index 000000000..7cb5bd75a --- /dev/null +++ b/lib/src/directives/directives/glitch.dart @@ -0,0 +1,101 @@ +import 'dart:async'; +import 'dart:math'; + +import 'package:flutter/material.dart'; + +class GlitchText extends StatefulWidget { + const GlitchText(this.text, {super.key, required this.style}); + + final String text; + final TextStyle style; + + @override + _GlitchTextState createState() => _GlitchTextState(); +} + +class _GlitchTextState extends State { + final _random = Random(); + late Timer _positionTimer; + late Timer _shadowTimer; + double _offsetX = 0; + double _offsetY = 0; + double _shadowOffsetX = 0; + double _shadowOffsetY = 0; + double _scale = 1.0; + + @override + void initState() { + super.initState(); + _positionTimer = + Timer.periodic(const Duration(milliseconds: 100), _randomizePosition); + _shadowTimer = + Timer.periodic(const Duration(milliseconds: 80), _randomizeShadow); + } + + void _randomizePosition(Timer timer) { + setState(() { + _offsetX = _random.nextDouble() * 10 - 5; + _offsetY = _random.nextDouble() * 10 - 5; + _scale = 1 + (_random.nextDouble() * 0.1 - 0.095); + }); + } + + void _randomizeShadow(Timer timer) { + setState(() { + _shadowOffsetX = _random.nextDouble() * 10 - 1; + _shadowOffsetY = _random.nextDouble() * 10 - 1; + }); + } + + @override + void dispose() { + _positionTimer.cancel(); + _shadowTimer.cancel(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Transform( + transform: Matrix4.identity() + ..translate(_offsetX, _offsetY) + ..scale(_scale), + child: Text( + widget.text, + style: widget.style.copyWith( + shadows: [ + Shadow( + color: Colors.red.withOpacity(0.6), + offset: Offset(_shadowOffsetX, _shadowOffsetY), + blurRadius: 0, + ), + Shadow( + color: Colors.blue.withOpacity(0.6), + offset: Offset(-_shadowOffsetX, -_shadowOffsetY), + blurRadius: 0, + ), + ], + decoration: _random.nextBool() + ? TextDecoration.underline + : TextDecoration.lineThrough, + decorationColor: Colors.white, + decorationThickness: _random.nextDouble() * 5 - 1, + ), + ), + ); + } +} + +void main() { + runApp(MaterialApp( + home: Scaffold( + appBar: AppBar(title: const Text('Glitch Effect')), + body: const Center( + child: GlitchText( + 'GLITCH', + style: TextStyle(fontSize: 80, fontWeight: FontWeight.bold), + ), + ), + ), + )); +} diff --git a/lib/src/directives/text_directive.dart b/lib/src/directives/text_directive.dart new file mode 100644 index 000000000..d5156e896 --- /dev/null +++ b/lib/src/directives/text_directive.dart @@ -0,0 +1,81 @@ +import '../attributes/attribute.dart'; +import '../factory/mix_provider_data.dart'; +import '../helpers/extensions/string_ext.dart'; +import 'directive_attribute.dart'; + +class UppercaseDirective extends TextDirective { + const UppercaseDirective(); + + @override + String modify(String value) => value.toUpperCase(); +} + +class CapitalizeDirective extends TextDirective { + const CapitalizeDirective(); + + @override + String modify(String value) => value.capitalize; +} + +class LowercaseDirective extends TextDirective { + const LowercaseDirective(); + + @override + String modify(String value) => value.toLowerCase(); +} + +class SentenceCaseDirective extends TextDirective { + const SentenceCaseDirective(); + + @override + String modify(String value) => value.sentenceCase; +} + +class TitleCaseDirective extends TextDirective { + const TitleCaseDirective(); + @override + String modify(String value) => value.titleCase; +} + +abstract class TextDirective extends Directive { + const TextDirective(); + + @override + String modify(String value); + + @override + get props => [modify]; +} + +class TextDirectiveAttribute + extends DirectiveAttribute { + const TextDirectiveAttribute(super.value); + + @override + TextDirectiveAttribute create(List value) { + return TextDirectiveAttribute(value); + } +} + +abstract class DirectiveAttribute> extends VisualAttribute> { + final List value; + const DirectiveAttribute(this.value); + + // Create method + T create(List value); + + @override + List resolve(MixData mix) => value; + + @override + T merge(covariant T? other) { + if (other == null) return this as T; + final combinedList = [...value, ...other.value]; + + return create(combinedList); + } + + @override + get props => [value]; +} diff --git a/lib/src/dtos/border/border.dto.dart b/lib/src/dtos/border/border.dto.dart deleted file mode 100644 index 7ecda39f7..000000000 --- a/lib/src/dtos/border/border.dto.dart +++ /dev/null @@ -1,207 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../../factory/mix_provider_data.dart'; -import '../color.dto.dart'; -import 'border_side.dto.dart'; -import 'box_border.dto.dart'; - -class BorderDto extends BoxBorderDto { - final BorderSideDto? top; - final BorderSideDto? right; - final BorderSideDto? bottom; - final BorderSideDto? left; - - const BorderDto._({ - this.bottom, - this.left, - this.right, - this.top, - }); - - const BorderDto.only({ - this.top, - this.right, - this.bottom, - this.left, - }); - - const BorderDto.symmetric({ - BorderSideDto? vertical, - BorderSideDto? horizontal, - }) : this.only( - top: vertical, - right: horizontal, - bottom: vertical, - left: horizontal, - ); - - const BorderDto.fromBorderSide(BorderSideDto side) - : this.only( - top: side, - right: side, - bottom: side, - left: side, - ); - - factory BorderDto.all({ - ColorDto? color, - double? width, - BorderStyle? style, - }) { - return BorderDto.fromBorderSide( - BorderSideDto.only( - color: color, - width: width, - style: style, - ), - ); - } - - factory BorderDto.from(Border border) { - return BorderDto.only( - top: BorderSideDto.from(border.top), - right: BorderSideDto.from(border.right), - bottom: BorderSideDto.from(border.bottom), - left: BorderSideDto.from(border.left), - ); - } - - BorderSideDto? get _top => top; - - BorderSideDto? get _bottom => bottom; - - BorderSideDto? get _left => left; - - BorderSideDto? get _right => right; - - @override - Border resolve(MixData mix) { - return Border( - top: _top?.resolve(mix) ?? BorderSide.none, - right: _right?.resolve(mix) ?? BorderSide.none, - bottom: _bottom?.resolve(mix) ?? BorderSide.none, - left: _left?.resolve(mix) ?? BorderSide.none, - ); - } - - BorderDto copyWith({ - BorderSideDto? top, - BorderSideDto? right, - BorderSideDto? bottom, - BorderSideDto? left, - }) { - return BorderDto._( - top: _top?.merge(top) ?? top, - right: _right?.merge(right) ?? right, - bottom: _bottom?.merge(bottom) ?? bottom, - left: _left?.merge(left) ?? left, - ); - } - - @override - get props => [_top, _right, _bottom, _left]; -} - -class BorderDirectionalDto extends BoxBorderDto { - final BorderSideDto? top; - final BorderSideDto? bottom; - final BorderSideDto? start; - final BorderSideDto? end; - - const BorderDirectionalDto._({ - this.top, - this.bottom, - this.start, - this.end, - }); - - factory BorderDirectionalDto.from(BorderDirectional border) { - return BorderDirectionalDto.only( - top: BorderSideDto.from(border.top), - bottom: BorderSideDto.from(border.bottom), - start: BorderSideDto.from(border.start), - end: BorderSideDto.from(border.end), - ); - } - - static BorderDirectionalDto? maybeFrom(BorderDirectional? border) { - if (border == null) { - return null; - } - - return BorderDirectionalDto.from(border); - } - - const BorderDirectionalDto.only({ - this.top, - this.bottom, - this.start, - this.end, - }); - - const BorderDirectionalDto.fromBorderSide(BorderSideDto side) - : this.only( - top: side, - bottom: side, - start: side, - end: side, - ); - - factory BorderDirectionalDto.all({ - ColorDto? color, - double? width, - BorderStyle? style, - }) { - return BorderDirectionalDto.fromBorderSide( - BorderSideDto.only( - color: color, - width: width, - style: style, - ), - ); - } - - factory BorderDirectionalDto.fromBorder(BorderDirectional border) { - return BorderDirectionalDto.only( - top: BorderSideDto.from(border.top), - bottom: BorderSideDto.from(border.bottom), - start: BorderSideDto.from(border.start), - end: BorderSideDto.from(border.end), - ); - } - - BorderSideDto? get _top => top; - - BorderSideDto? get _bottom => bottom; - - BorderSideDto? get _start => start; - - BorderSideDto? get _end => end; - - @override - BorderDirectional resolve(MixData mix) { - return BorderDirectional( - top: _top?.resolve(mix) ?? BorderSide.none, - bottom: _bottom?.resolve(mix) ?? BorderSide.none, - start: _start?.resolve(mix) ?? BorderSide.none, - end: _end?.resolve(mix) ?? BorderSide.none, - ); - } - - BorderDirectionalDto copyWith({ - BorderSideDto? top, - BorderSideDto? bottom, - BorderSideDto? start, - BorderSideDto? end, - }) { - return BorderDirectionalDto._( - top: _top?.merge(top) ?? top, - bottom: _bottom?.merge(bottom) ?? bottom, - start: _start?.merge(start) ?? start, - end: _end?.merge(end) ?? end, - ); - } - - @override - get props => [_top, _bottom, _start, _end]; -} diff --git a/lib/src/dtos/border/border_side.dto.dart b/lib/src/dtos/border/border_side.dto.dart deleted file mode 100644 index c64ae58fe..000000000 --- a/lib/src/dtos/border/border_side.dto.dart +++ /dev/null @@ -1,76 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../../factory/mix_provider_data.dart'; -import '../color.dto.dart'; -import '../dto.dart'; - -class BorderSideDto extends Dto { - final ColorDto? color; - final double? width; - final BorderStyle? style; - - final double? strokeAlign; - - const BorderSideDto._({ - this.color, - this.width, - this.style, - this.strokeAlign, - }); - - const BorderSideDto.only({ - this.color, - this.width, - this.style, - this.strokeAlign, - }); - - factory BorderSideDto.from(BorderSide side) { - return BorderSideDto.only( - color: ColorDto(side.color), - width: side.width, - style: side.style, - strokeAlign: side.strokeAlign, - ); - } - - BorderSideDto copyWith({ - ColorDto? color, - double? width, - BorderStyle? style, - double? strokeAlign, - }) { - return BorderSideDto._( - color: color ?? this.color, - width: width ?? this.width, - style: style ?? this.style, - strokeAlign: strokeAlign ?? this.strokeAlign, - ); - } - - BorderSideDto merge(BorderSideDto? other) { - if (other == null) return this; - - return copyWith( - color: other.color, - width: other.width, - style: other.style, - strokeAlign: other.strokeAlign, - ); - } - - final BorderSide _default = const BorderSide(); - - @override - BorderSide resolve(MixData mix) { - return BorderSide( - color: color?.resolve(mix) ?? _default.color, - width: width ?? _default.width, - style: style ?? _default.style, - strokeAlign: strokeAlign ?? _default.strokeAlign, - ); - } - - @override - get props => [color, width, style, strokeAlign]; -} diff --git a/lib/src/dtos/border/box_border.dto.dart b/lib/src/dtos/border/box_border.dto.dart deleted file mode 100644 index 245f46992..000000000 --- a/lib/src/dtos/border/box_border.dto.dart +++ /dev/null @@ -1,67 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../dto.dart'; -import 'border.dto.dart'; -import 'border_side.dto.dart'; - -enum BoxBorderSide { top, bottom, left, right, start, end } - -abstract class BoxBorderDto extends Dto { - const BoxBorderDto(); - - BorderSideDto? get _top; - BorderSideDto? get _bottom; - BorderSideDto? get _left; - BorderSideDto? get _right; - BorderSideDto? get _start; - BorderSideDto? get _end; - - static Dto from>(T border) { - if (border is Border) { - return BorderDto.from(border) as Dto; - } - if (border is BorderDirectional) { - return BorderDirectionalDto.from(border) as Dto; - } - - throw UnsupportedError( - "${border.runtimeType} is not suppported, use Border or BorderDirectional", - ); - } - - static Dto? maybeFrom>( - T? border, - ) { - if (border == null) { - return null; - } - - return from(border); - } - - BoxBorderDto merge(BoxBorderDto? other) { - if (other == null || other == this) return this; - - if (other is BorderDirectionalDto) { - return BorderDirectionalDto.only( - top: other.top ?? _top, - bottom: other.bottom ?? _bottom, - start: other.start ?? _start, - end: other.end ?? _end, - ); - } - - if (other is BorderDto) { - return BorderDto.only( - top: other.top ?? _top, - bottom: other.bottom ?? _bottom, - left: other.left ?? _left, - right: other.right ?? _right, - ); - } - - throw UnsupportedError( - "${other.runtimeType} is not supported, use EdgeInsetsDto or EdgeInsetsDirectionalDto", - ); - } -} diff --git a/lib/src/dtos/color.dto.dart b/lib/src/dtos/color.dto.dart deleted file mode 100644 index ae9b71b0e..000000000 --- a/lib/src/dtos/color.dto.dart +++ /dev/null @@ -1,53 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../factory/mix_provider_data.dart'; -import '../theme/tokens/color_token.dart'; -import 'double.dto.dart'; -import 'dto.dart'; - -class ColorDto extends Dto { - final Color value; - - // Modifier is only used after value is resolved. - final ValueModifier? _directive; - - const ColorDto( - this.value, { - ValueModifier? directive, - }) : _directive = directive; - - const ColorDto.from( - Color color, { - ValueModifier? directive, - }) : value = color, - _directive = directive; - - // Helper utility for internal API usage - static ColorDto? maybeFrom( - Color? color, { - ValueModifier? directive, - }) { - if (color == null) { - return null; - } - - return ColorDto.from( - color, - directive: directive, - ); - } - - @override - Color resolve(MixData mix) { - var resolvedColor = value; - - if (resolvedColor is ColorToken) { - resolvedColor = mix.resolveToken.color(resolvedColor); - } - - return _directive?.call(resolvedColor) ?? resolvedColor; - } - - @override - get props => [value]; -} diff --git a/lib/src/dtos/double.dto.dart b/lib/src/dtos/double.dto.dart deleted file mode 100644 index b9583974a..000000000 --- a/lib/src/dtos/double.dto.dart +++ /dev/null @@ -1,41 +0,0 @@ -import '../factory/mix_provider_data.dart'; -import 'dto.dart'; - -typedef ValueModifier = T Function(T value); - -@Deprecated('Remove this for now') -class DoubleDto extends Dto { - final double _value; - - // Modifier is only used after value is resolved. - final ValueModifier? _modifier; - - const DoubleDto( - double value, { - ValueModifier? directive, - }) : _value = value, - _modifier = directive; - - const DoubleDto.from( - double value, { - ValueModifier? directiv, - }) : _value = value, - _modifier = null; - - static DoubleDto? maybeFrom(double? value) { - if (value == null) return null; - - return DoubleDto(value); - } - - @override - double resolve(MixData mix) { - final modifier = _modifier; - - // Apply modifier if it exists - return modifier != null ? modifier(_value) : _value; - } - - @override - get props => [_value, _modifier]; -} diff --git a/lib/src/dtos/dto.dart b/lib/src/dtos/dto.dart deleted file mode 100644 index 2f54ea14e..000000000 --- a/lib/src/dtos/dto.dart +++ /dev/null @@ -1,8 +0,0 @@ -import '../factory/mix_provider_data.dart'; -import '../helpers/equality_mixin/equality_mixin.dart'; - -abstract class Dto with EqualityMixin { - const Dto(); - - T resolve(MixData mix); -} diff --git a/lib/src/dtos/edge_insets/edge_insets.dto.dart b/lib/src/dtos/edge_insets/edge_insets.dto.dart deleted file mode 100644 index 833b83006..000000000 --- a/lib/src/dtos/edge_insets/edge_insets.dto.dart +++ /dev/null @@ -1,102 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../../factory/mix_provider_data.dart'; -import 'edge_insets_geometry.dto.dart'; - -class EdgeInsetsDto extends EdgeInsetsGeometryDto { - final double? top; - final double? bottom; - final double? left; - final double? right; - - const EdgeInsetsDto._({ - this.top, - this.bottom, - this.left, - this.right, - }); - - const EdgeInsetsDto.only({ - this.top, - this.bottom, - this.left, - this.right, - }); - - const EdgeInsetsDto.all(double value) - : top = value, - bottom = value, - left = value, - right = value; - - const EdgeInsetsDto.symmetric({ - double? horizontal, - double? vertical, - }) : top = vertical, - bottom = vertical, - left = horizontal, - right = horizontal; - - factory EdgeInsetsDto.from(EdgeInsets edgeInsets) { - return EdgeInsetsDto._( - top: doubleNullIfZero(edgeInsets.top), - bottom: doubleNullIfZero(edgeInsets.bottom), - left: doubleNullIfZero(edgeInsets.left), - right: doubleNullIfZero(edgeInsets.right), - ); - } - - // Helper utility for internal API use and cleaner conditional checking - static EdgeInsetsDto? maybeFrom(EdgeInsets? edgeInsets) { - if (edgeInsets == null) return null; - - return EdgeInsetsDto.from(edgeInsets); - } - - double? get _top => top; - - double? get _bottom => bottom; - - double? get _left => left; - - double? get _right => right; - - EdgeInsetsDto copyWith({ - double? top, - double? bottom, - double? left, - double? right, - }) { - return EdgeInsetsDto._( - top: top ?? this.top, - bottom: bottom ?? this.bottom, - left: left ?? this.left, - right: right ?? this.right, - ); - } - - @override - EdgeInsetsDto merge(EdgeInsetsDto? other) { - if (other == null) return this; - - return copyWith( - top: other.top, - bottom: other.bottom, - left: other.left, - right: other.right, - ); - } - - @override - EdgeInsets resolve(MixData mix) { - return EdgeInsets.only( - top: mix.resolveToken.space(_top ?? 0.0), - bottom: mix.resolveToken.space(_bottom ?? 0.0), - left: mix.resolveToken.space(_left ?? 0.0), - right: mix.resolveToken.space(_right ?? 0.0), - ); - } - - @override - get props => [top, bottom, left, right]; -} diff --git a/lib/src/dtos/edge_insets/edge_insets_directional.dto.dart b/lib/src/dtos/edge_insets/edge_insets_directional.dto.dart deleted file mode 100644 index a9ab071f2..000000000 --- a/lib/src/dtos/edge_insets/edge_insets_directional.dto.dart +++ /dev/null @@ -1,109 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../../factory/mix_provider_data.dart'; -import 'edge_insets_geometry.dto.dart'; - -class EdgeInsetsDirectionalDto - extends EdgeInsetsGeometryDto { - final double? top; - final double? bottom; - final double? start; - final double? end; - - const EdgeInsetsDirectionalDto._({ - this.top, - this.bottom, - this.start, - this.end, - }); - - const EdgeInsetsDirectionalDto.only({ - this.top, - this.bottom, - this.start, - this.end, - }); - - const EdgeInsetsDirectionalDto.all(double value) - : this._( - top: value, - bottom: value, - start: value, - end: value, - ); - - const EdgeInsetsDirectionalDto.symmetric({ - double? horizontal, - double? vertical, - }) : this._( - top: vertical, - bottom: vertical, - start: horizontal, - end: horizontal, - ); - - factory EdgeInsetsDirectionalDto.from( - EdgeInsetsDirectional edgeInsets, - ) { - return EdgeInsetsDirectionalDto._( - top: doubleNullIfZero(edgeInsets.top), - bottom: doubleNullIfZero(edgeInsets.bottom), - start: doubleNullIfZero(edgeInsets.start), - end: doubleNullIfZero(edgeInsets.end), - ); - } - - double? get _top => top; - - double? get _bottom => bottom; - - /* - double? get _left => null; - - double? get _right => null; - */ - - double? get _start => start; - - double? get _end => end; - - - EdgeInsetsDirectionalDto copyWith({ - double? top, - double? bottom, - double? start, - double? end, - }) { - return EdgeInsetsDirectionalDto._( - top: top ?? this.top, - bottom: bottom ?? this.bottom, - start: start ?? this.start, - end: end ?? this.end, - ); - } - - @override - EdgeInsetsDirectionalDto merge(EdgeInsetsDirectionalDto? other) { - if (other == null) return this; - - return copyWith( - top: other.top, - bottom: other.bottom, - start: other.start, - end: other.end, - ); - } - - @override - EdgeInsetsDirectional resolve(MixData mix) { - return EdgeInsetsDirectional.only( - top: mix.resolveToken.space(_top ?? 0.0), - bottom: mix.resolveToken.space(_bottom ?? 0.0), - start: mix.resolveToken.space(_start ?? 0.0), - end: mix.resolveToken.space(_end ?? 0.0), - ); - } - - @override - get props => [top, bottom, start, end]; -} diff --git a/lib/src/dtos/edge_insets/edge_insets_geometry.dto.dart b/lib/src/dtos/edge_insets/edge_insets_geometry.dto.dart deleted file mode 100644 index 3b63c5ae8..000000000 --- a/lib/src/dtos/edge_insets/edge_insets_geometry.dto.dart +++ /dev/null @@ -1,79 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../dto.dart'; -import 'edge_insets.dto.dart'; -import 'edge_insets_directional.dto.dart'; - -abstract class EdgeInsetsGeometryDto - extends Dto { - const EdgeInsetsGeometryDto(); - - double? get _top; - double? get _bottom; - double? get _left; - double? get _right; - double? get _start; - double? get _end; - - //bool get _isDirectional => - // (_start != null || _end != null) && (_left == null && _right == null); - - static D - from>( - T edgeInsets, - ) { - if (edgeInsets is EdgeInsets) { - return EdgeInsetsDto.from(edgeInsets) as D; - } - if (edgeInsets is EdgeInsetsDirectional) { - return EdgeInsetsDirectionalDto.from(edgeInsets) as D; - } - - throw UnsupportedError( - "${edgeInsets.runtimeType} is not suppported, use EdgeInsets or EdgeInsetsDirectional", - ); - } - - static D? maybeFrom>( - T? edgeInsets, - ) { - if (edgeInsets == null) return null; - - return from(edgeInsets); - } - - EdgeInsetsGeometryDto merge(covariant EdgeInsetsGeometryDto? other) { - if (other == null) return this; - - if (other is EdgeInsetsDirectionalDto && this is EdgeInsetsDirectionalDto) { - return EdgeInsetsDirectionalDto.only( - top: other.top ?? _top, - bottom: other.bottom ?? _bottom, - start: other.start ?? _start, - end: other.end ?? _end, - ); - } - if (other is EdgeInsetsDto && this is EdgeInsetsDto) { - return EdgeInsetsDto.only( - top: other.top ?? _top, - bottom: other.bottom ?? _bottom, - left: other.left ?? _left, - right: other.right ?? _right, - ); - } - - throw UnsupportedError( - "${other.runtimeType} is not supported, use EdgeInsetsDto or EdgeInsetsDirectionalDto, and both mergeable types must be the same", - ); - } - - @override - get props => [_top, _bottom, _left, _right, _start, _end]; -} - -double? doubleNullIfZero(double? value) { - if (value == null || value == 0.0) return null; - - return value; -} diff --git a/lib/src/dtos/radius/border_radius.dto.dart b/lib/src/dtos/radius/border_radius.dto.dart deleted file mode 100644 index 9f76e099a..000000000 --- a/lib/src/dtos/radius/border_radius.dto.dart +++ /dev/null @@ -1,113 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../../factory/mix_provider_data.dart'; -import 'border_radius_geometry.dto.dart'; -import 'radius_dto.dart'; - -class BorderRadiusDto extends BorderRadiusGeometryDto { - final RadiusDto? _topLeft; - final RadiusDto? _topRight; - final RadiusDto? _bottomLeft; - final RadiusDto? _bottomRight; - - const BorderRadiusDto.only({ - RadiusDto? topLeft, - RadiusDto? topRight, - RadiusDto? bottomLeft, - RadiusDto? bottomRight, - }) : _topLeft = topLeft, - _topRight = topRight, - _bottomLeft = bottomLeft, - _bottomRight = bottomRight; - - factory BorderRadiusDto.from(BorderRadius borderRadius) { - return BorderRadiusDto.only( - topLeft: RadiusDto.from(borderRadius.topLeft), - topRight: RadiusDto.from(borderRadius.topRight), - bottomLeft: RadiusDto.from(borderRadius.bottomLeft), - bottomRight: RadiusDto.from(borderRadius.bottomRight), - ); - } - - /// A border radius with all zero radii. - static const BorderRadiusDto zero = BorderRadiusDto.all(RadiusDto.zero()); - - const BorderRadiusDto.all(RadiusDto radius) - : this.only( - topLeft: radius, - topRight: radius, - bottomLeft: radius, - bottomRight: radius, - ); - - const BorderRadiusDto.vertical({ - RadiusDto? top, - RadiusDto? bottom, - }) : this.only( - topLeft: top, - topRight: top, - bottomLeft: bottom, - bottomRight: bottom, - ); - - const BorderRadiusDto.horizontal({ - RadiusDto? left, - RadiusDto? right, - }) : this.only( - topLeft: left, - topRight: right, - bottomLeft: left, - bottomRight: right, - ); - - @override - RadiusDto? get bottomLeft => _bottomLeft; - - @override - RadiusDto? get bottomRight => _bottomRight; - - @override - RadiusDto? get topLeft => _topLeft; - - @override - RadiusDto? get topRight => _topRight; - - @override - RadiusDto? get bottomStart => null; - - @override - RadiusDto? get bottomEnd => null; - - @override - RadiusDto? get topEnd => null; - - @override - RadiusDto? get topStart => null; - - @override - BorderRadius resolve(MixData mix) { - return BorderRadius.only( - topLeft: topLeft?.resolve(mix) ?? Radius.zero, - topRight: topRight?.resolve(mix) ?? Radius.zero, - bottomLeft: bottomLeft?.resolve(mix) ?? Radius.zero, - bottomRight: bottomRight?.resolve(mix) ?? Radius.zero, - ); - } - - BorderRadiusDto copyWith({ - RadiusDto? topLeft, - RadiusDto? topRight, - RadiusDto? bottomLeft, - RadiusDto? bottomRight, - }) { - return BorderRadiusDto.only( - topLeft: topLeft ?? this.topLeft, - topRight: topRight ?? this.topRight, - bottomLeft: bottomLeft ?? this.bottomLeft, - bottomRight: bottomRight ?? this.bottomRight, - ); - } - - @override - get props => [topLeft, topRight, bottomLeft, bottomRight]; -} diff --git a/lib/src/dtos/radius/border_radius_directional.dto.dart b/lib/src/dtos/radius/border_radius_directional.dto.dart deleted file mode 100644 index 2ab437943..000000000 --- a/lib/src/dtos/radius/border_radius_directional.dto.dart +++ /dev/null @@ -1,124 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../../factory/mix_provider_data.dart'; -import 'border_radius_geometry.dto.dart'; -import 'radius_dto.dart'; - -class BorderRadiusDirectionalDto - extends BorderRadiusGeometryDto { - final RadiusDto? _topStart; - final RadiusDto? _topEnd; - final RadiusDto? _bottomStart; - final RadiusDto? _bottomEnd; - - factory BorderRadiusDirectionalDto.from( - BorderRadiusDirectional borderRadiusDirectional, - ) { - return BorderRadiusDirectionalDto.only( - topStart: RadiusDto.from(borderRadiusDirectional.topStart), - topEnd: RadiusDto.from(borderRadiusDirectional.topEnd), - bottomStart: RadiusDto.from(borderRadiusDirectional.bottomStart), - bottomEnd: RadiusDto.from(borderRadiusDirectional.bottomEnd), - ); - } - - static maybeFrom(BorderRadiusDirectional? borderRadiusDirectional) { - if (borderRadiusDirectional == null) return null; - - return BorderRadiusDirectionalDto.from(borderRadiusDirectional); - } - - const BorderRadiusDirectionalDto.only({ - RadiusDto? topStart, - RadiusDto? topEnd, - RadiusDto? bottomStart, - RadiusDto? bottomEnd, - }) : _topStart = topStart, - _topEnd = topEnd, - _bottomStart = bottomStart, - _bottomEnd = bottomEnd; - - const BorderRadiusDirectionalDto.all(RadiusDto radius) - : this.only( - topStart: radius, - topEnd: radius, - bottomStart: radius, - bottomEnd: radius, - ); - - const BorderRadiusDirectionalDto.horizontal({ - RadiusDto? start, - RadiusDto? end, - }) : this.only( - topStart: start, - topEnd: end, - bottomStart: start, - bottomEnd: end, - ); - - const BorderRadiusDirectionalDto.vertical({ - RadiusDto? top, - RadiusDto? bottom, - }) : this.only( - topStart: top, - topEnd: top, - bottomStart: bottom, - bottomEnd: bottom, - ); - - @override - RadiusDto? get bottomEnd => _bottomEnd; - - @override - RadiusDto? get bottomLeft => null; - - @override - RadiusDto? get bottomRight => null; - - @override - RadiusDto? get bottomStart => _bottomStart; - - @override - RadiusDto? get topEnd => _topEnd; - - @override - RadiusDto? get topLeft => null; - - @override - RadiusDto? get topRight => null; - - @override - RadiusDto? get topStart => _topStart; - - @override - BorderRadiusDirectional resolve(MixData mix) { - return BorderRadiusDirectional.only( - topStart: topStart?.resolve(mix) ?? Radius.zero, - topEnd: topEnd?.resolve(mix) ?? Radius.zero, - bottomStart: bottomStart?.resolve(mix) ?? Radius.zero, - bottomEnd: bottomEnd?.resolve(mix) ?? Radius.zero, - ); - } - - BorderRadiusDirectionalDto copyWith({ - RadiusDto? topStart, - RadiusDto? topEnd, - RadiusDto? bottomStart, - RadiusDto? bottomEnd, - }) { - return BorderRadiusDirectionalDto.only( - topStart: topStart ?? this.topStart, - topEnd: topEnd ?? this.topEnd, - bottomStart: bottomStart ?? this.bottomStart, - bottomEnd: bottomEnd ?? this.bottomEnd, - ); - } - - @override - List get props => [ - topStart, - topEnd, - bottomStart, - bottomEnd, - ]; -} diff --git a/lib/src/dtos/radius/border_radius_geometry.dto.dart b/lib/src/dtos/radius/border_radius_geometry.dto.dart deleted file mode 100644 index e8ab508cf..000000000 --- a/lib/src/dtos/radius/border_radius_geometry.dto.dart +++ /dev/null @@ -1,78 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../dto.dart'; -import 'border_radius.dto.dart'; -import 'border_radius_directional.dto.dart'; -import 'radius_dto.dart'; - -abstract class BorderRadiusGeometryDto - extends Dto { - const BorderRadiusGeometryDto(); - - RadiusDto? get topLeft => null; - RadiusDto? get topRight => null; - RadiusDto? get bottomLeft => null; - RadiusDto? get bottomRight => null; - RadiusDto? get topStart => null; - RadiusDto? get topEnd => null; - RadiusDto? get bottomStart => null; - RadiusDto? get bottomEnd => null; - - static Dto from>(T borderRadius) { - if (borderRadius is BorderRadius) { - return BorderRadiusDto.from(borderRadius) as Dto; - } - if (borderRadius is BorderRadiusDirectional) { - return BorderRadiusDirectionalDto.from(borderRadius) as Dto; - } - throw UnsupportedError( - "${borderRadius.runtimeType} is not supported, use BorderRadius or BorderRadiusDirectional", - ); - } - - static Dto? maybeFrom>(T? borderRadius) { - if (borderRadius == null) { - return null; - } - - return BorderRadiusGeometryDto.from(borderRadius); - } - - bool get isDirectional => - (topStart != null || - topEnd != null || - bottomStart != null || - bottomEnd != null) && - (topLeft == null && - topRight == null && - bottomLeft == null && - bottomRight == null); - - BorderRadiusGeometryDto merge(BorderRadiusGeometryDto? other) { - if (other == null || other == this) return this; - - if (other is BorderRadiusDto) { - return BorderRadiusDto.only( - topLeft: other.topLeft ?? topLeft, - topRight: other.topRight ?? topRight, - bottomLeft: other.bottomLeft ?? bottomLeft, - bottomRight: other.bottomRight ?? bottomRight, - ); - } - - if (other is BorderRadiusDirectionalDto) { - return BorderRadiusDirectionalDto.only( - topStart: other.topStart ?? topStart, - topEnd: other.topEnd ?? topEnd, - bottomStart: other.bottomStart ?? bottomStart, - bottomEnd: other.bottomEnd ?? bottomEnd, - ); - } - - throw UnsupportedError( - "${other.runtimeType} is unsupported, use BorderRadiusDto or BorderRadiusDirectionalDto", - ); - } -} diff --git a/lib/src/dtos/radius/radius_dto.dart b/lib/src/dtos/radius/radius_dto.dart deleted file mode 100644 index 5ed39aa54..000000000 --- a/lib/src/dtos/radius/radius_dto.dart +++ /dev/null @@ -1,59 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../../factory/mix_provider_data.dart'; -import '../dto.dart'; - -class RadiusDto extends Dto { - /// The radius value on the horizontal axis. - final double _x; - - /// The radius value on the vertical axis. - final double _y; - - const RadiusDto.circular(double radius) : this.elliptical(radius, radius); - - const RadiusDto.zero() - : this.elliptical( - 0, - 0, - ); - - /// Constructs an elliptical radius with the given radii. - const RadiusDto.elliptical(double x, double y) - : _x = x, - _y = y; - - factory RadiusDto.from(Radius radius) { - if (radius.x == radius.y) { - return RadiusDto.circular( - radius.x, - ); - } - - return RadiusDto.elliptical( - radius.x, - radius.y, - ); - } - - static RadiusDto? maybeFrom(Radius? radius) { - if (radius == null) return null; - - return RadiusDto.from(radius); - } - - @override - Radius resolve(MixData mix) { - final resolvedX = _x; - final resolvedY = _y; - - if (resolvedX == 0 && resolvedY == 0) { - return Radius.zero; - } - - return Radius.elliptical(resolvedX, resolvedY); - } - - @override - get props => [_x, _y]; -} diff --git a/lib/src/dtos/shadow/box_shadow.dto.dart b/lib/src/dtos/shadow/box_shadow.dto.dart deleted file mode 100644 index b3d4c6724..000000000 --- a/lib/src/dtos/shadow/box_shadow.dto.dart +++ /dev/null @@ -1,78 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../../factory/mix_provider_data.dart'; -import '../../helpers/mergeable_list.dart'; -import '../color.dto.dart'; -import 'shadow.dto.dart'; - -class BoxShadowDto extends ShadowDto { - final double? spreadRadius; - - const BoxShadowDto({ - super.color, - super.offset, - super.blurRadius, - this.spreadRadius, - }); - - factory BoxShadowDto.fromBoxShadow(BoxShadow? boxShadow) { - if (boxShadow == null) { - return const BoxShadowDto(); - } - - return BoxShadowDto( - blurRadius: boxShadow.blurRadius, - color: ColorDto.maybeFrom(boxShadow.color), - offset: Offset(boxShadow.offset.dx, boxShadow.offset.dy), - spreadRadius: boxShadow.spreadRadius, - ); - } - - @override - BoxShadow resolve(MixData mix) { - return BoxShadow( - color: color?.resolve(mix) ?? const BoxShadow().color, - offset: offset ?? const BoxShadow().offset, - blurRadius: blurRadius ?? const BoxShadow().blurRadius, - spreadRadius: spreadRadius ?? const BoxShadow().spreadRadius, - ); - } - - @override - BoxShadowDto copyWith({ - ColorDto? color, - Offset? offset, - double? blurRadius, - double? spreadRadius, - }) { - return BoxShadowDto( - color: color ?? this.color, - offset: offset ?? this.offset, - blurRadius: blurRadius ?? this.blurRadius, - spreadRadius: spreadRadius ?? this.spreadRadius, - ); - } - - @override - BoxShadowDto merge(BoxShadowDto? other) { - return copyWith( - color: other?.color, - offset: other?.offset, - blurRadius: other?.blurRadius, - spreadRadius: other?.spreadRadius, - ); - } - - @override - get props => [color, offset, blurRadius, spreadRadius]; -} - -extension BoxShadowDtoExt on List { - List resolve(MixData mix) { - return map((e) => e.resolve(mix)).toList(); - } - - List merge(List? other) { - return combineMergeableLists(this, other); - } -} diff --git a/lib/src/dtos/shadow/shadow.dto.dart b/lib/src/dtos/shadow/shadow.dto.dart deleted file mode 100644 index 3841306a4..000000000 --- a/lib/src/dtos/shadow/shadow.dto.dart +++ /dev/null @@ -1,77 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../../../mix.dart'; -import '../../helpers/mergeable_list.dart'; -import '../color.dto.dart'; -import '../dto.dart'; - -class ShadowDto extends Dto with Mergeable { - final ColorDto? color; - final Offset? offset; - final double? blurRadius; - - const ShadowDto({ - this.color, - this.offset, - this.blurRadius, - }); - - factory ShadowDto.from(Shadow shadow) { - return ShadowDto( - blurRadius: shadow.blurRadius, - color: ColorDto.maybeFrom(shadow.color), - offset: shadow.offset, - ); - } - - static maybeFrom(Shadow? shadow) { - if (shadow == null) { - return null; - } - - return ShadowDto.from(shadow); - } - - @override - T resolve(MixData mix) { - return Shadow( - color: color?.resolve(mix) ?? const Shadow().color, - offset: offset ?? const Shadow().offset, - blurRadius: blurRadius ?? const Shadow().blurRadius, - ) as T; - } - - ShadowDto copyWith({ - ColorDto? color, - Offset? offset, - double? blurRadius, - }) { - return ShadowDto( - color: color ?? this.color, - offset: offset ?? this.offset, - blurRadius: blurRadius ?? this.blurRadius, - ); - } - - @override - ShadowDto merge(covariant ShadowDto? other) { - return copyWith( - color: other?.color, - offset: other?.offset, - blurRadius: other?.blurRadius, - ); - } - - @override - get props => [color, offset, blurRadius]; -} - -extension ShadowDtoExt on List { - List resolve(MixData mix) { - return map((e) => e.resolve(mix)).toList(); - } - - List merge(List? other) { - return combineMergeableLists(this, other); - } -} diff --git a/lib/src/dtos/text_style.dto.dart b/lib/src/dtos/text_style.dto.dart deleted file mode 100644 index b6d5c90fb..000000000 --- a/lib/src/dtos/text_style.dto.dart +++ /dev/null @@ -1,252 +0,0 @@ -import 'dart:ui'; - -import 'package:flutter/material.dart'; - -import '../../mix.dart'; -import 'color.dto.dart'; -import 'dto.dart'; -import 'shadow/shadow.dto.dart'; - -class TextStyleDto extends Dto { - final String? fontFamily; - final FontWeight? fontWeight; - - final bool? inherit; - final FontStyle? fontStyle; - final double? fontSize; - final double? letterSpacing; - final double? wordSpacing; - final TextBaseline? textBaseline; - final ColorDto? color; - final ColorDto? backgroundColor; - final List? shadows; - final List? fontFeatures; - final TextDecoration? decoration; - final ColorDto? decorationColor; - final TextDecorationStyle? decorationStyle; - final Locale? locale; - final String? debugLabel; - final double? height; - final Paint? foreground; - final Paint? background; - final double? decorationThickness; - final List? fontFamilyFallback; - - final TextStyleToken? styleToken; - - const TextStyleDto({ - this.inherit, - this.fontFamily, - this.fontWeight, - this.fontStyle, - this.fontSize, - this.letterSpacing, - this.wordSpacing, - this.textBaseline, - this.color, - this.backgroundColor, - this.shadows, - this.fontFeatures, - this.decoration, - this.decorationColor, - this.decorationStyle, - this.debugLabel, - this.locale, - this.height, - this.foreground, - this.background, - this.decorationThickness, - this.fontFamilyFallback, - this.styleToken, - }); - - factory TextStyleDto.from(TextStyle style) { - if (style is TextStyleToken) { - return TextStyleDto(styleToken: style); - } - - return TextStyleDto( - fontFamily: style.fontFamily, - inherit: style.inherit, - fontWeight: style.fontWeight, - fontStyle: style.fontStyle, - fontSize: style.fontSize, - background: style.background, - foreground: style.foreground, - letterSpacing: style.letterSpacing, - wordSpacing: style.wordSpacing, - textBaseline: style.textBaseline, - color: ColorDto.maybeFrom(style.color), - backgroundColor: ColorDto.maybeFrom(style.backgroundColor), - decorationColor: ColorDto.maybeFrom(style.decorationColor), - shadows: style.shadows?.map((e) => ShadowDto.from(e)).toList(), - fontFeatures: style.fontFeatures, - decoration: style.decoration, - decorationStyle: style.decorationStyle, - debugLabel: style.debugLabel, - locale: style.locale, - height: style.height, - decorationThickness: style.decorationThickness, - fontFamilyFallback: style.fontFamilyFallback, - ); - } - - static maybeFrom(TextStyle? style) { - return style != null ? TextStyleDto.from(style) : null; - } - - bool get hasToken => styleToken != null; - - @override - TextStyle resolve(MixData mix) { - TextStyleDto? styleRef; - - if (styleToken != null) { - // Load as DTO for consistent merging behavior - final textStyle = mix.resolveToken.textStyle(styleToken!); - styleRef = TextStyleDto.from(textStyle); - } - - // If there is a style token, use it as a base - if (styleRef != null) { - styleRef = styleRef.merge(this); - } else { - // If not just reference itself - styleRef = this; - } - - return TextStyle( - inherit: styleRef.inherit ?? true, - fontFamily: styleRef.fontFamily, - fontWeight: styleRef.fontWeight, - fontStyle: styleRef.fontStyle, - fontSize: styleRef.fontSize, - letterSpacing: styleRef.letterSpacing, - height: styleRef.height, - wordSpacing: styleRef.wordSpacing, - textBaseline: styleRef.textBaseline, - color: styleRef.color?.resolve(mix), - backgroundColor: styleRef.backgroundColor?.resolve(mix), - shadows: styleRef.shadows?.map((e) => e.resolve(mix)).toList(), - fontFeatures: styleRef.fontFeatures, - decoration: styleRef.decoration, - decorationColor: styleRef.decorationColor?.resolve(mix), - decorationStyle: styleRef.decorationStyle, - debugLabel: styleRef.debugLabel, - background: styleRef.background, - foreground: styleRef.foreground, - locale: styleRef.locale, - decorationThickness: styleRef.decorationThickness, - fontFamilyFallback: styleRef.fontFamilyFallback, - ); - } - - TextStyleDto copyWith({ - String? fontFamily, - bool? inherit, - FontWeight? fontWeight, - FontStyle? fontStyle, - double? fontSize, - double? letterSpacing, - double? wordSpacing, - TextBaseline? textBaseline, - ColorDto? color, - ColorDto? backgroundColor, - List? shadows, - List? fontFeatures, - TextDecoration? decoration, - ColorDto? decorationColor, - TextDecorationStyle? decorationStyle, - String? debugLabel, - Locale? locale, - double? height, - Paint? background, - Paint? foreground, - double? decorationThickness, - List? fontFamilyFallback, - TextStyleToken? styleToken, - }) { - return TextStyleDto( - inherit: inherit ?? this.inherit, - fontFamily: fontFamily ?? this.fontFamily, - fontWeight: fontWeight ?? this.fontWeight, - fontStyle: fontStyle ?? this.fontStyle, - fontSize: fontSize ?? this.fontSize, - letterSpacing: letterSpacing ?? this.letterSpacing, - wordSpacing: wordSpacing ?? this.wordSpacing, - textBaseline: textBaseline ?? this.textBaseline, - color: color ?? this.color, - backgroundColor: backgroundColor ?? this.backgroundColor, - shadows: this.shadows?.merge(shadows) ?? shadows, - fontFeatures: fontFeatures ?? this.fontFeatures, - decoration: decoration ?? this.decoration, - decorationColor: decorationColor ?? this.decorationColor, - decorationStyle: decorationStyle ?? this.decorationStyle, - debugLabel: debugLabel ?? this.debugLabel, - locale: locale ?? this.locale, - height: height ?? this.height, - background: background ?? this.background, - foreground: foreground ?? this.foreground, - decorationThickness: decorationThickness ?? this.decorationThickness, - fontFamilyFallback: [...?this.fontFamilyFallback, ...?fontFamilyFallback], - styleToken: styleToken ?? this.styleToken, - ); - } - - TextStyleDto merge(TextStyleDto? other) { - if (other == null) return this; - - return copyWith( - fontFamily: other.fontFamily, - inherit: other.inherit, - fontWeight: other.fontWeight, - fontStyle: other.fontStyle, - fontSize: other.fontSize, - height: other.height, - letterSpacing: other.letterSpacing, - wordSpacing: other.wordSpacing, - textBaseline: other.textBaseline, - color: other.color, - backgroundColor: other.backgroundColor, - shadows: other.shadows, - fontFeatures: other.fontFeatures, - decoration: other.decoration, - decorationColor: other.decorationColor, - decorationStyle: other.decorationStyle, - debugLabel: other.debugLabel, - locale: other.locale, - background: other.background, - foreground: other.foreground, - decorationThickness: other.decorationThickness, - fontFamilyFallback: other.fontFamilyFallback, - styleToken: other.styleToken, - ); - } - - @override - get props => [ - fontFamily, - inherit, - fontWeight, - fontStyle, - fontSize, - letterSpacing, - wordSpacing, - textBaseline, - color, - backgroundColor, - shadows, - fontFeatures, - decoration, - decorationColor, - decorationStyle, - debugLabel, - locale, - height, - background, - foreground, - decorationThickness, - fontFamilyFallback, - styleToken, - ]; -} diff --git a/lib/src/extensions/build_context_ext.dart b/lib/src/extensions/build_context_ext.dart deleted file mode 100644 index 689486035..000000000 --- a/lib/src/extensions/build_context_ext.dart +++ /dev/null @@ -1,88 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../attributes/shared/shared.descriptor.dart'; -import '../factory/mix_provider.dart'; -import '../factory/mix_provider_data.dart'; -import '../theme/mix_theme.dart'; -import '../widgets/container/container.descriptor.dart'; -import '../widgets/flex/flex.descriptor.dart'; -import '../widgets/icon/icon.descriptor.dart'; -import '../widgets/image/image.descriptor.dart'; -import '../widgets/stack/stack.descriptor.dart'; -import '../widgets/text/text.descriptor.dart'; - -extension BuildContextExt on BuildContext { - MixData? get mix => MixProvider.of(this); - - /// MEDIA QUERY EXTENSION METHODS - - /// MediaQueryData for context - MediaQueryData get mq => MediaQuery.of(this); - - /// Directionality of context - TextDirection get directionality => Directionality.of(this); - - /// Orientation of the device - Orientation get orientation => mq.orientation; - - /// Is device in landscape mode. - - bool get isLandscape => orientation == Orientation.landscape; - - /// Is device in portrait mode. - - bool get isPortrait => orientation == Orientation.portrait; - - /// Screen width - double get screenWidth => mq.size.width; - - /// Screen height - double get screenHeight => mq.size.height; - - // Theme Context Extensions - - Brightness get brightness => Theme.of(this).brightness; - - /// Check if brightness is Brightness.dark - bool get isDarkMode => brightness == Brightness.dark; - - /// Theme context helpers - ThemeData get theme => Theme.of(this); - - /// Theme color scheme - ColorScheme get colorScheme => theme.colorScheme; - - /// Theme text theme - TextTheme get textTheme => theme.textTheme; - - /// Mix Theme Data - MixThemeData get mixTheme => MixTheme.of(this); - - @Deprecated('use SharedProps.fromContext(context) instead') - CommonDescriptor get sharedProps => - CommonDescriptor.fromContext(MixProvider.of(this)!); - - @Deprecated('use BoxProps.fromContext(context) instead') - StyledContainerDescriptor get boxProps => - StyledContainerDescriptor.fromContext(MixProvider.of(this)!); - - @Deprecated('use FlexProps.fromContext(context) instead') - StyledFlexDescriptor get flexProps => - StyledFlexDescriptor.fromContext(MixProvider.of(this)!); - - @Deprecated('use ZBoxProps.fromContext(context) instead') - StyledStackDescriptor get zBoxProps => - StyledStackDescriptor.fromContext(MixProvider.of(this)!); - - @Deprecated('use IconProps.fromContext(context) instead') - StyledIconDescriptor get iconProps => - StyledIconDescriptor.fromContext(MixProvider.of(this)!); - - @Deprecated('use TextProps.fromContext(context) instead') - StyledTextDescriptor get textProps => - StyledTextDescriptor.fromContext(MixProvider.of(this)!); - - @Deprecated('use ImageProps.fromContext(context) instead') - StyledImageDescriptor get imageProps => - StyledImageDescriptor.fromContext(MixProvider.of(this)!); -} diff --git a/lib/src/extensions/exports.dart b/lib/src/extensions/exports.dart deleted file mode 100644 index 9e1f8a1b8..000000000 --- a/lib/src/extensions/exports.dart +++ /dev/null @@ -1,3 +0,0 @@ -export 'build_context_ext.dart'; -export 'helper_ext.dart'; -export 'style_mix_ext.dart'; diff --git a/lib/src/extensions/helper_ext.dart b/lib/src/extensions/helper_ext.dart deleted file mode 100644 index 2cd112662..000000000 --- a/lib/src/extensions/helper_ext.dart +++ /dev/null @@ -1,48 +0,0 @@ -import 'package:flutter/material.dart'; - -extension StrutStyleExt on StrutStyle { - StrutStyle merge(StrutStyle? other) { - return StrutStyle( - fontFamily: other?.fontFamily ?? fontFamily, - fontFamilyFallback: other?.fontFamilyFallback ?? fontFamilyFallback, - fontSize: other?.fontSize ?? fontSize, - height: other?.height ?? height, - leadingDistribution: other?.leadingDistribution ?? leadingDistribution, - leading: other?.leading ?? leading, - fontWeight: other?.fontWeight ?? fontWeight, - fontStyle: other?.fontStyle ?? fontStyle, - forceStrutHeight: other?.forceStrutHeight ?? forceStrutHeight, - debugLabel: other?.debugLabel ?? debugLabel, - ); - } -} - -extension Matrix4Ext on Matrix4 { - /// Merge [other] into this matrix. - Matrix4 merge(Matrix4? other) { - if (other == null || other == this) return this; - - return clone()..multiply(other); - } -} - -extension IterableExt on Iterable { - Iterable sorted([Comparator? compare]) { - List newList = List.from(this); - newList.sort(compare); - - return newList; - } -} - -extension ListExt on List { - T? firstWhereOrNull(bool Function(T) test) { - for (T element in this) { - if (test(element)) { - return element; - } - } - - return null; - } -} diff --git a/lib/src/factory/exports.dart b/lib/src/factory/exports.dart deleted file mode 100644 index 7b898ed92..000000000 --- a/lib/src/factory/exports.dart +++ /dev/null @@ -1,4 +0,0 @@ -export 'mix_provider_data.dart'; -export 'style_group.dart'; -export 'style_mix.dart'; -export 'style_mix_data.dart'; diff --git a/lib/src/factory/mix_provider.dart b/lib/src/factory/mix_provider.dart index 940750497..6dec7b2ba 100644 --- a/lib/src/factory/mix_provider.dart +++ b/lib/src/factory/mix_provider.dart @@ -1,56 +1,72 @@ +// ignore_for_file: prefer-widget-private-members + import 'package:flutter/material.dart'; import 'mix_provider_data.dart'; +import 'style_mix.dart'; + +typedef MixBuilder = Widget Function(MixData mixData); /// Context data widget for Mix data. /// /// Inherits from [InheritedWidget] and stores [data], a value that can be /// accessed by widgets through the static method `of()` or by ensuring it is /// present with `ensureOf()`. -class MixProvider extends InheritedWidget { - /// Initializes a new instance of [MixProvider]. +class Mix extends InheritedWidget { + /// Initializes a new instance of [Mix]. /// /// The `data` parameter is the [MixData] object to store. [child] /// receives the element tree that will use this context, and [key] can be set /// to track changes. - const MixProvider( - this.data, { - Key? key, - required Widget child, - }) : super(key: key, child: child); - - /// Contains the context data object. - final MixData? data; + const Mix({required this.data, required super.child, super.key}); /// Returns the context data from the widget tree in [context]. /// - /// This method returns the first instance of [MixProvider] that it finds + /// This method returns the first instance of [Mix] that it finds /// while searching up the widget tree. Returns null if not found. - static MixData? of(BuildContext context) { - final widget = context.dependOnInheritedWidgetOfExactType(); - - return widget?.data; + static MixData? maybeOf(BuildContext context) { + return context.dependOnInheritedWidgetOfExactType()?.data; } - /// Ensures that [MixProvider] is available on the widget tree starting at + /// Ensures that [Mix] is available on the widget tree starting at /// the given [context]. /// - /// Throws an exception if [MixProvider] is not found within the given widget + /// Throws an exception if [Mix] is not found within the given widget /// tree containing [context]. - static MixData ensureOf(BuildContext context) { - final data = of(context); + static MixData of(BuildContext context) { + final mixData = maybeOf(context); - if (data == null) { - throw Exception('MixData not found in widget tree'); + if (mixData == null) { + throw Exception('MixProvider not found in widget tree'); } - return data; + return mixData; } + /// Contains the context data object. + final MixData? data; + @override - bool updateShouldNotify(MixProvider oldWidget) { + bool updateShouldNotify(Mix oldWidget) { // Returns true if the `mixProvider` inside the widget has changed since // the last time a dependent overridden method was called. return data != oldWidget.data; } + + static Mix build( + BuildContext context, { + required StyleMix style, + required MixBuilder builder, + bool inherit = false, + }) { + MixData mixData = MixData.create(context, style); + if (inherit) { + final contextMixData = Mix.maybeOf(context); + if (contextMixData != null) { + mixData = contextMixData.merge(mixData); + } + } + + return Mix(data: mixData, child: builder(mixData)); + } } diff --git a/lib/src/factory/mix_provider_data.dart b/lib/src/factory/mix_provider_data.dart index 9a0dd4a6d..0291b8245 100644 --- a/lib/src/factory/mix_provider_data.dart +++ b/lib/src/factory/mix_provider_data.dart @@ -1,122 +1,112 @@ +// Necessary packages are imported at the start of the file. import 'package:flutter/material.dart'; import '../attributes/attribute.dart'; +import '../attributes/variant_attribute.dart'; +import '../core/attributes_map.dart'; +import '../core/equality/compare_mixin.dart'; import '../decorators/decorator.dart'; -import '../helpers/equality_mixin/equality_mixin.dart'; -import '../helpers/mergeable_map.dart'; import '../theme/mix_theme.dart'; -import '../variants/variant_attribute.dart'; import 'style_mix.dart'; -import 'style_mix_data.dart'; -@Deprecated('Use MixData instead.') -typedef MixContext = MixData; +/// This class is used for encapsulating all [MixData] related operations. +/// It contains a mixture of properties and methods useful for handling different attributes, +/// decorators and token resolvers. +@immutable +class MixData with Comparable { + // Instance variables for widget attributes, widget decorators and token resolver. + final VisualAttributeMap _attributes; -class MixData with EqualityMixin { - final MergeableMap _widgetAttributes; - final MergeableMap _widgetDecorators; - final MixTokenResolver _tokenResolver; + final MixTokenResolver _resolver; + /// A Private constructor for the [MixData] class t hat initializes its main variables. + /// + /// It takes in [attributes], [decorators] and [resolver] as required parameters. MixData._({ - required MergeableMap widgetAttributes, - required MergeableMap widgetDecorators, - required MixTokenResolver tokenResolver, - }) : _widgetAttributes = widgetAttributes, - _widgetDecorators = widgetDecorators, - _tokenResolver = tokenResolver; - - factory MixData.create({ - required BuildContext context, - required StyleMix style, - }) { - // Tracks the values selected and does not allow for - // attributes already expended to be expended again. - final currentValues = StyleMixData( - attributes: style.values.attributes, - decorators: style.values.decorators, - variants: [], - contextVariants: [], - ); - - final attributes = _applyContextVariants( - context, - style.values.contextVariants, - ); + required MixTokenResolver resolver, + required VisualAttributeMap attributes, + }) : _attributes = attributes, + _resolver = resolver; - final combinedValues = currentValues.merge(StyleMixData.create(attributes)); + factory MixData.create(BuildContext context, StyleMix style) { + final styleMix = applyContextToVisualAttributes(context, style); return MixData._( - widgetAttributes: combinedValues.attributes ?? MergeableMap([]), - widgetDecorators: combinedValues.decorators ?? MergeableMap([]), - tokenResolver: MixTokenResolver(context), + resolver: MixTokenResolver(context), + attributes: VisualAttributeMap(styleMix), ); } - MixTokenResolver get resolveToken => _tokenResolver; - - static List _applyContextVariants( - BuildContext context, - Iterable attributes, - ) { - // Use the fold method to reduce the input attributes list - // into a single list of expanded attributes. - return attributes.fold>( - [], // Initial empty list to accumulate the result. - (expanded, attribute) { - // Check if the current attribute is a ContextVariantAttribute. - if (attribute is ContextVariantAttribute) { - // Determine if the attribute should be applied based on the context. - final shouldApply = attribute.shouldApply(context); - - // If willApply is true, recursively apply context variants to - // the attribute's value and add the result to the expanded list. - // Otherwise, add the attribute itself to the list. - return expanded - ..addAll(shouldApply - ? _applyContextVariants(context, attribute.value.toAttributes()) - : [attribute]); - } else { - // If the current attribute is not a ContextVariantAttribute, - // simply add it to the expanded list. - return expanded..add(attribute); - } - }, - ); + /// Getter method for [MixTokenResolver]. + /// + /// Returns current [_resolver]. + MixTokenResolver get resolver => _resolver; + + /// A getter method for [_attributes]. + /// + /// Returns a list of all [VisualAttribute]. + @visibleForTesting + VisualAttributeMap get attributes => _attributes; + + /// A getter method for [_decorators]. + /// + /// Returns a list of all [Decorator]. + List decoratorOfType() => + _attributes.whereType().toList(); + + /// Retrieves an instance of the specified [VisualAttribute] type from the [MixData]. + /// d + /// Accepts a type parameter [Attr] which extends [VisualAttribute]. + /// Returns the instance of type [Attr] if found, else returns null. + T? attributeOfType() { + return _attributes.attributeOfType(); } - /// Returns an instance of the specified [StyledWidgetAttributes] type from the [MixData]. - A? attributesOfType() { - return _widgetAttributes[A] as A?; + R? get, R>() { + return attributeOfType()?.resolve(this); + } + + /// This is similar to a merge behavior however it prioritizes the current properties + /// over the other properties, essentially using [MixData] `other` as the base for this instance. + /// + /// [other] is the other [MixData] instance that is to be merged with current instance. + /// Returns a new instance of [MixData] which is actually a merge of current and other instance. + MixData merge(MixData other) { + return MixData._( + resolver: _resolver, + attributes: _attributes.merge(other._attributes), + ); } - T dependOnAttributesOfType() { - final attribute = attributesOfType(); + /// Overrides the getter function of [props] from [Comparable] to specify properties necessary for distinguishing instances. + /// + /// Returns a list of properties [_attributes] & [_decorators]. + @override + get props => [_attributes]; +} - if (attribute is! T) { - throw ''' - No $T could be found starting from MixContext - when call mixContext.attributesOfType<$T>(). This can happen because you - have not create a Mix with $T. - '''; - } +@visibleForTesting +List applyContextToVisualAttributes( + BuildContext context, + StyleMix mix, +) { + StyleMix style = StyleMix.create(mix.styles); - return attribute; + final contextVariants = mix.variants.whereType(); + final multiVariants = mix.variants.whereType(); + + // Once there are no more context variants to apply, return the mix + if (contextVariants.isEmpty) { + return mix.styles; } - List? get decorators { - return _widgetDecorators.values.toList(); + for (ContextVariantAttribute attr in contextVariants) { + if (attr.when(context)) style = style.merge(attr.value); } - /// This is similar to a merge behavior however it prioritizes the current properties - /// over the other properties, essentially using [MixData] `other` as the base for this instance. - MixData inheritFrom(MixData other) { - return MixData._( - widgetAttributes: other._widgetAttributes.merge(_widgetAttributes), - widgetDecorators: other._widgetDecorators.merge(_widgetDecorators), - tokenResolver: _tokenResolver, - ); + for (MultiVariantAttribute attr in multiVariants) { + if (attr.when(context)) style = style.merge(attr.value); } - @override - get props => [_widgetAttributes, _widgetDecorators]; + return applyContextToVisualAttributes(context, style); } diff --git a/lib/src/factory/style_group.dart b/lib/src/factory/style_group.dart index 816a49104..9d727b401 100644 --- a/lib/src/factory/style_group.dart +++ b/lib/src/factory/style_group.dart @@ -5,7 +5,7 @@ abstract class StyleGroup> { StyleGroup merge(covariant StyleGroup? other); - StyleGroup selectVariants(List variants); + StyleGroup selectVariants(List variants); StyleGroup copyWith(); } diff --git a/lib/src/factory/style_mix.dart b/lib/src/factory/style_mix.dart index 257a44664..f2bbcba2a 100644 --- a/lib/src/factory/style_mix.dart +++ b/lib/src/factory/style_mix.dart @@ -1,268 +1,415 @@ -// ignore_for_file: non_constant_identifier_names, constant_identifier_names, long-parameter-list +// ignore_for_file: non_constant_identifier_names, constant_identifier_names, long-parameter-list, prefer-named-boolean-parameters -import '/mix.dart'; -import '../variants/variant_attribute.dart'; +import 'package:flutter/foundation.dart'; -@Deprecated( - 'Use StyleMix instead. ' - 'This class will be removed in a future release.', -) -typedef Mix = StyleMix; +import '../../mix.dart'; -/// A class representing a mix of attributes, decorators, variants, context -/// variants, and directives. +/// A utility class for managing a collection of styling attributes and variants. /// -/// The `MixFactory` class is primarily used for constructing styling attributes and -/// variants. This class provides a set of factory -/// constructors and utility methods for working with mixes. +/// The `StyleMix` class is used to encapsulate a set of styling attributes and +/// variants which can be applied to a widget. This class provides several +/// factory constructors and utility methods to help create, manipulate, and +/// merge collections of styling attributes and variants. +/// +/// Example: +/// ```dart +/// final style = StyleMix.create([...]); +/// final updatedStyle = style.selectVariant(myVariant); +/// ``` class StyleMix { - final StyleMixData _values; + /// A constant, empty mix for use with const constructor widgets. + /// + /// This can be used as a default or initial value where a `StyleMix` is required. + static const empty = StyleMix._(styles: [], variants: []); - const StyleMix._(StyleMixData values) : _values = values; + /// A map of visual attributes contained in this mix. + final List styles; - /// A constant, empty mix for use with const constructor widgets. - static const StyleMix constant = StyleMix._(StyleMixData.empty()); + /// A map of variant attributes contained in this mix. + final List variants; + + const StyleMix._({required this.styles, required this.variants}); - // Factory constructors + /// Creates a new `StyleMix` instance with a specified list of [Attribute]s. + /// + /// This factory constructor initializes a `StyleMix` with a list of + /// attributes provided as individual parameters. Only non-null attributes + /// are included in the resulting `StyleMix`. + /// + /// There is no specific reason for only 20 parameters. This is just a + /// reasonable number of parameters to support. If you need more than 20, + /// consider breaking up your mixes into many style mixes that can be applied + /// + /// Example: + /// ```dart + /// final style = StyleMix(attribute1, attribute2, attribute3); + /// ``` factory StyleMix([ - StyleAttribute? p1, - StyleAttribute? p2, - StyleAttribute? p3, - StyleAttribute? p4, - StyleAttribute? p5, - StyleAttribute? p6, - StyleAttribute? p7, - StyleAttribute? p8, - StyleAttribute? p9, - StyleAttribute? p10, - StyleAttribute? p11, - StyleAttribute? p12, + Attribute? p1, + Attribute? p2, + Attribute? p3, + Attribute? p4, + Attribute? p5, + Attribute? p6, + Attribute? p7, + Attribute? p8, + Attribute? p9, + Attribute? p10, + Attribute? p11, + Attribute? p12, + Attribute? p13, + Attribute? p14, + Attribute? p15, + Attribute? p16, + Attribute? p17, + Attribute? p18, + Attribute? p19, + Attribute? p20, ]) { - final params = []; + final params = [ + p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, // + p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, + ].whereType(); + + return StyleMix.create(params); + } - for (final param in [p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12]) { - if (param != null) params.add(param); + /// Constructs a `StyleMix` from an iterable of [Attribute] instances. + /// + /// This factory constructor segregates the attributes into visual and variant + /// attributes, initializing a new `StyleMix` with these segregated collections. + /// + /// Example: + /// ```dart + /// final style = StyleMix.create([attribute1, attribute2]); + /// ``` + factory StyleMix.create(Iterable attributes) { + final variantList = []; + final styleList = []; + + for (final attribute in attributes) { + if (attribute is VisualAttribute) { + styleList.add(attribute); + } else if (attribute is VariantAttribute) { + variantList.add(attribute); + } else if (attribute is StyleMixAttribute) { + variantList.addAll(attribute.value.variants); + styleList.addAll(attribute.value.styles); + } else { + assert(false, 'Unsupported attribute type: $attribute'); + } } - return StyleMix.fromAttributes(params); + return StyleMix._(styles: styleList, variants: variantList); } - /// Constructs a mix from a non-null iterable of [StyleAttribute] instances. - factory StyleMix.fromAttributes(Iterable attributes) { - return StyleMix._(StyleMixData.create(attributes)); + /// Selects a mix based on a [condition]. + /// + /// Returns [fallback] if the [condition] is true, otherwise returns [style]. + /// + /// Example: + /// ```dart + /// final style = StyleMix.chooser(condition, style, fallbackStyle); + /// ``` + factory StyleMix.chooser( + bool condition, + StyleMix style, [ + StyleMix? fallback, + ]) { + return condition ? style : fallback ?? StyleMix.empty; } - factory StyleMix.fromValues(StyleMixData values) { - return StyleMix._(values); + /// Combines an optional positional list of [mixes] into a single `StyleMix`. + /// + /// This factory constructor iterates through the list of [mixes] params, merging + /// each mix with the previous mix and returning the final combined `StyleMix`. + /// + /// Example: + /// ```dart + /// final combinedStyle = StyleMix.combineList([style1, style2, style3]); + /// ``` + factory StyleMix.combineList(Iterable mixes) { + return mixes.isEmpty + ? StyleMix.empty + : mixes.reduce((combinedStyle, mix) => combinedStyle.merge(mix)); } - /// Returns an iterable of [StyleAttribute] instances from this MixFactory. - Iterable toAttributes() { - return _values.toAttributes(); - } + /// Combines an optional positional list of [StyleMix] instances into a single `StyleMix`. + /// + /// This factory constructor iterates through the non-null parameters, merging + /// each `StyleMix` instance with the previous one and returning the final combined `StyleMix`. + /// If a null value is provided for any of the parameters, it is ignored. + /// + /// Example: + /// ```dart + /// final style1 = StyleMix(...); + /// final style2 = StyleMix(...); + /// final style3 = StyleMix(...); + /// + /// final combinedStyle = StyleMix.combine(style1, style2, style3); + /// ``` + /// + /// In this example: + /// - Three `StyleMix` instances `style1`, `style2`, and `style3` are created. + /// - The `combine` factory constructor is called with `style1`, `style2`, and `style3` as arguments. + /// - The `combine` method returns a new `StyleMix` instance `combinedStyle` with the visual and variant attributes of `style1`, `style2`, and `style3` combined. + static SpreadFunctionParams get combine => + const SpreadFunctionParams(StyleMix.combineList); + + /// Returns a list of all attributes contained in this mix. + /// + /// This includes both visual and variant attributes. + Iterable get values => [...styles, ...variants]; - /// Returns a [StyleMixData] instance representing the values in this MixFactory. - StyleMixData get values => _values; + /// Returns true if this StyleMix does not contain any attributes or variants. + bool get isEmpty => styles.isEmpty && variants.isEmpty; - /// Returns a new mix with the provided [values] merged with this mix's values. - StyleMix copyWith({ - StyleMixData? values, - }) { - return StyleMix._(_values.merge(values)); - } + /// Returns false if this StyleMix contains any attributes or variants. + bool get isNotEmpty => !isEmpty; - /// Clones this mix into a new instance. - StyleMix clone() => StyleMix._(_values.clone()); + /// Returns the length of the list of attributes contained in this mix. + /// + /// This includes both visual and variant attributes. + int get length => values.length; - /// Merges this mix with the provided [mix] and returns the resulting MixFactory. - StyleMix merge(StyleMix mix) => StyleMix.combine([this, mix]); + /// Selects a single or positional params list of [Variant] and returns a new `StyleMix` with the selected variants. + /// + /// If the [variant] is not initially part of the `StyleMix`, this method returns this mix without any changes. + /// Otherwise, the method merges the attributes of the selected [variant] into a new `StyleMix` instance. + /// + /// Example: + /// ```dart + /// final outlined = Variant('outlined-button'); + /// final style = StyleMix( + /// attr1, + /// attr2, + /// outlined(attr4, attr5), + /// ); + /// final updatedStyle = style.selectVariant(outlined); + /// ``` + /// + /// In this example: + /// - An `outlined` instance `outlined` is created to represent an outlined button styling. + /// - An initial `StyleMix` instance `style` is created with `attr1` and `attr2`, along with the `outlined`. + /// - The `selectVariant` method is called on the `StyleMix` instance with `outlined` as the argument. + /// - The `selectVariant` method returns a new `StyleMix` instance `updatedStyle` with the attributes of the selected variant merged. + /// - The resulting `updatedStyle` is equivalent to `StyleMix(attr1, attr2, attr4, attr5)`. + /// + /// Note: + /// The attributes from the selected variant (`attr4` and `attr5`) are not applied to the `StyleMix` instance until the `selectVariant` method is called. + SpreadFunctionParams get selectVariant { + return SpreadFunctionParams(selectVariantList); + } - StyleMix mergeMany(List mixes) { - return StyleMix.combine([this, ...mixes]); + /// Returns a new `StyleMix` with the provided [styles] and [variants] merged with this mix's values. + /// + /// If [styles] or [variants] is null, the corresponding attribute map of this mix is used. + StyleMix copyWith({ + List? styles, + List? variants, + }) { + return StyleMix._( + styles: styles ?? this.styles, + variants: variants ?? this.variants, + ); } - /// Merges this mix with the provided nullable [style]. + /// Merges this mix with the provided [StyleMix] instances and returns the resulting `StyleMix`. + /// + /// This method combines the visual and variant attributes of this mix and the provided [StyleMix] instances. + /// If a null value is provided for any of the parameters, it is ignored. /// - /// If [style] is null, returns this MixFactory. Otherwise, merges [style] with this MixFactory. - StyleMix mergeNullable(StyleMix? style) => - style == null ? this : merge(style); + /// This method combines the visual and variant attributes of this mix and the provided [mix]. + StyleMix merge([StyleMix? mix]) { + if (mix == null) return this; - /// Selects a single [StyleVariant] and returns a new mix with the selected variant. - StyleMix selectVariant(StyleVariant variant) { - return selectVariants([variant]); + final mergedStyles = [...styles, ...mix.styles]; + final mergedVariants = [...variants, ...mix.variants]; + + return copyWith(styles: mergedStyles, variants: mergedVariants); } - /// Selects multiple [StyleVariant] instances and returns a new mix with the selected variants. + /// Selects multiple [Variant] instances and returns a new `StyleMix` with the selected variants. + /// + /// If the [selectVariantList] list is empty, returns this mix without any changes. + /// Otherwise, the method merges the attributes of the selected variants into a new `StyleMix` instance. + /// + /// Example: + /// final outlinedVariant = Variant('outlined'); + /// final smallVariant = Variant('small'); + /// final style = StyleMix( + /// attr1, + /// attr2, + /// outlinedVariant(attr3, attr4), + /// smallVariant(attr5), + /// ); + /// final outlinedSmallMix = style.selectVariants([outlinedVariant, smallVariant]); + /// ``` /// - /// If the [variants] list is empty, returns this mix without any changes. - StyleMix selectVariants(List variants) { - if (variants.isEmpty) { + /// In this example: + /// - Two `Variant` instances `outlinedVariant` and `smallVariant` are created. + /// - An initial `StyleMix` instance `style` is created with `attr1` and `attr2`, along with the two variants. + /// - The `selectVariants` method is called on the `StyleMix` instance with a list of `outlinedVariant` and `smallVariant` as the argument. + /// - The `selectVariants` method returns a new `StyleMix` instance `outlinedSmallMix` with the attributes of the selected variants merged. + /// - The resulting `outlinedSmallMix` is equivalent to `StyleMix(attr1, attr2, attr3, attr4, attr5)`. + /// + /// Note: + /// The attributes from the selected variants (`attr3`, `attr4`, and `attr5`) are not applied to the `StyleMix` instance until the `selectVariants` method is called. + StyleMix selectVariantList(Iterable selectedVariants) { + /// Return the original StyleMix if no variants were selected + if (selectedVariants.isEmpty) { return this; } - final existingVariants = [..._values.variants]; - final matchedVariants = []; - - for (final v in variants) { - existingVariants.removeWhere((e) { - if (e.variant == v) { - matchedVariants.add(e); - return true; + /// Initializing two empty lists that store the matched and remaining `Variants`, respectively. + final matchedVariants = []; + final remainingVariants = []; + + /// Convert the selected variants list into a set for efficient lookup. + /// A set does not contain duplicate elements and lookup time is O(1), making it faster than list lookup. + final selectedVariantSet = selectedVariants.toSet(); + + /// Loop over all VariantAttributes in variants only once instead of a nested loop, + /// checking if each one matches with the selected variants. + /// If it does, add it to the matchedVariants, else add it to remainingVariants. + for (final attr in variants) { + if (attr is MultiVariantAttribute) { + if (attr.matches(selectedVariants)) { + // if all variants match, add it to the matchedVariants + matchedVariants.add(attr); + } else { + // Remove any matching variants and add it as a new MultiVariantAttribute + // This allows to multiple matching variants to be removed + // For multi pass matching + remainingVariants.add(attr.remove(selectedVariants)); } - - return false; - }); + } else { + if (selectedVariantSet.contains(attr.variant)) { + matchedVariants.add(attr); + } else { + remainingVariants.add(attr); + } + } } - // Create a mix from the matched variants - final mixToApply = StyleMix.fromVariantAttributes(matchedVariants); - - // Create a mix with the existing values - final existingMix = StyleMix._( - StyleMixData( - attributes: _values.attributes, - decorators: _values.decorators, - variants: existingVariants, - contextVariants: _values.contextVariants, - ), + final updatedStyle = StyleMix._( + styles: styles, + variants: remainingVariants, ); - // Merge the existing mix with the mix to apply - return existingMix.merge(mixToApply); - } - - StyleMix pickVariants(List variants) { - final matchedVariants = []; + /// If not a single variant was matched, return the original StyleMix. + if (matchedVariants.isEmpty) { + return updatedStyle; + } - final currentVariants = _values.variants; + /// Create a StyleMix from the matched variants. + final styleToApply = + StyleMix.combineList(matchedVariants.map((e) => e.value).toList()); - for (final variantAttr in currentVariants) { - if (variants.contains(variantAttr.variant)) { - matchedVariants.add(variantAttr); - } - } + /// Merge the new StyleMix created with the existing StyleMix, excluding the matched variants. + final mergedStyle = updatedStyle.merge(styleToApply); - // Create a mix from the matched variants - return StyleMix.fromVariantAttributes(matchedVariants); + /// Apply all variants and return the final StyleMix. + return mergedStyle.selectVariantList(selectedVariants); } - /// Selects variants based on a condition and returns a new mix with the selected variants. - StyleMix selectVariantCondition( - Map cases, - ) { - final keys = cases.keys.toList(); - final values = cases.values.toList(); + /// Picks and applies only the attributes within the specified [Variant] instances, and returns a new `StyleMix`. + /// + /// Unlike `selectVariants`, `pickVariants` ignores all other attributes initially present in the `StyleMix`. + /// + /// If the list of [pickVariants] is empty, returns a new empty `StyleMix`. + /// + /// Example: + /// ```dart + /// final outlinedVariant = Variant('outlined'); + /// final smallVariant = Variant('small'); + /// final style = StyleMix(attr1, attr2, outlinedVariant(buttonAttr1, buttonAttr2), smallVariant(buttonAttr3)); + /// final pickedMix = style.pickVariants([outlinedVariant, smallVariant]); + /// ``` + /// + /// In this example: + /// - Two `Variant` instances `outlinedVariant` and `smallVariant` are created. + /// - An initial `StyleMix` instance `style` is created with `attr1` and `attr2`, along with the two variants. + /// - The `pickVariants` method is called on the `StyleMix` instance with a list of `outlinedVariant` and `smallVariant` as the argument. + /// - The `pickVariants` method returns a new `StyleMix` instance `pickedMix` with only the attributes of the selected variants, ignoring `attr1` and `attr2`. + /// - The resulting `pickedMix` is equivalent to `StyleMix(buttonAttr1, buttonAttr2, buttonAttr3)`. + /// + /// Note: + /// The attributes `attr1` and `attr2` from the initial `StyleMix` are ignored, and only the attributes within the specified variants are picked and applied to the new `StyleMix`. + StyleMix pickVariants( + List pickedVariants, { + bool isRecursive = false, + }) { + final matchedVariants = []; - List variants = []; + // Return an empty StyleMix if the list of picked variants is empty - for (var i = 0; i < keys.length; i++) { - if (keys[i]) { - variants.add(values[i]); + for (final variantAttr in variants) { + if (pickedVariants.contains(variantAttr.variant)) { + matchedVariants.add(variantAttr); } } + if (pickedVariants.isEmpty || matchedVariants.isEmpty) { + return isRecursive ? this : StyleMix.empty; + } - return selectVariants(variants); - } + final pickedStyle = + StyleMix.combineList(matchedVariants.map((e) => e.value)); - factory StyleMix.fromVariantAttributes(List variants) { - return StyleMix.combine(variants.map((e) => e.value).toList()); + return pickedStyle.pickVariants(pickedVariants, isRecursive: true); } - /// Chooses a mix based on a [condition]. + /// Selects variants based on a [cases] map and returns a new `StyleMix` with the selected variants. /// - /// Returns [ifTrue] if the [condition] is true, otherwise returns [ifFalse]. - factory StyleMix.chooser({ - required bool condition, - required StyleMix ifTrue, - required StyleMix ifFalse, - }) { - if (condition) { - return ifTrue; - } else { - return ifFalse; - } - } - - /// Combines a list of [mixes] into a single MixFactory. + /// The [cases] list contains [SwitchCondition] instances, each of which contains a boolean [condition] and a [Variant]. + /// If a condition is true, the corresponding [Variant] is selected. + /// + /// Example: + /// ```dart + /// final highContrastVariant = Variant('highContrast'); + /// final largeFontVariant = Variant('largeFont'); /// - /// Iterates through the list of mixes, merging each mix with the previous mix - /// and returning the final combined MixFactory. - factory StyleMix.combine(List mixes) { - StyleMixData combinedValues = const StyleMixData.empty(); - for (final mix in mixes) { - combinedValues = combinedValues.merge(mix.values); + /// final style = StyleMix(); + /// final updatedStyle = style.variantSwitcher([ + /// const ConditionChooser(useHighContrast, highContrastVariant), + /// const ConditionChooser(useLargeFont, largeFontVariant) + /// ]); + /// ``` + /// + /// In this example: + /// - Two `Variant` instances are created to represent high contrast and large font styling preferences. + /// - An initial `StyleMix` instance is created. + /// - The `variantSwitcher` method is called on the `StyleMix` instance with a map of conditions and variants. + /// - The conditions `useHighContratst` and `useLargeFont` are hypothetical boolean values representing user preferences. + /// - If a condition is true, the corresponding `Variant` is selected and applied to the `StyleMix` instance, creating an `updatedStyle` instance with the selected variants. + StyleMix variantSwitcher(List> cases) { + List variantsToApply = []; + + for (SwitchCondition conditionCase in cases) { + if (conditionCase.condition) { + variantsToApply.add(conditionCase.value); + } } - return StyleMix.fromValues(combinedValues); + return selectVariantList(variantsToApply); } @override bool operator ==(Object other) { if (identical(this, other)) return true; - return other is StyleMix && other._values == _values; + return other is StyleMix && + listEquals(styles, other.styles) && + listEquals(variants, other.variants); } @override - int get hashCode => _values.hashCode; + int get hashCode => styles.hashCode ^ variants.hashCode; } -extension DeprecatedMixExtension on StyleMix { - /// Adds an Attribute to a Mix - @Deprecated('Simplifying the mix API to avoid confusion. Use apply instead') - SpreadPositionalParams get mix { - return SpreadPositionalParams(addAttributes); - } - - @Deprecated('Use selectVariants now') - StyleMix withVariants(List variants) { - return withManyVariants(variants); - } - - @Deprecated( - 'Use merge() or mergeMany() now. You might have to turn into a Mix first. firstMixFactory.merge(secondMix)', - ) - StyleMix addAttributes(List attributes) { - final newValues = StyleMixData.create(attributes); +class SwitchCondition { + final bool condition; + final T value; - return StyleMix._(_values.merge(newValues)); - } - - @Deprecated('Use selectVariants now') - StyleMix withManyVariants(List variants) { - return selectVariants(variants); - } - - @Deprecated('Use merge() or mergeMany() instead') - SpreadPositionalParams get apply => - SpreadPositionalParams(mergeMany); - - @Deprecated('Use selectVariant now') - StyleMix withVariant(StyleVariant variant) { - return selectVariant(variant); - } - - @Deprecated('Use combine now') - StyleMix combineAll(List mixes) { - return StyleMix.combine(mixes); - } - - @Deprecated('Use selectVariant now') - StyleMix withMaybeVariant(StyleVariant? variant) { - if (variant == null) return this; - - return withVariant(variant); - } - - @Deprecated('Use mergeNullable instead') - StyleMix maybeApply(StyleMix? mix) { - if (mix == null) return this; - - return apply(mix); - } - - @Deprecated('Use applyNullable instead') - StyleMix applyMaybe(StyleMix? mix) { - return maybeApply(mix); - } + const SwitchCondition(this.condition, this.value); } diff --git a/lib/src/factory/style_mix_data.dart b/lib/src/factory/style_mix_data.dart deleted file mode 100644 index 58de40fc0..000000000 --- a/lib/src/factory/style_mix_data.dart +++ /dev/null @@ -1,125 +0,0 @@ -import '../../mix.dart'; -import '../decorators/decorator.dart'; -import '../helpers/equality_mixin/equality_mixin.dart'; -import '../helpers/mergeable_map.dart'; -import '../variants/variant_attribute.dart'; - -class StyleMixData with EqualityMixin { - final MergeableMap? attributes; - final MergeableMap? decorators; - final List variants; - final List contextVariants; - - const StyleMixData({ - required this.attributes, - required this.decorators, - required this.variants, - required this.contextVariants, - }); - - /// Creates a new [StyleMixData] instance from the provided [Iterable] of [StyleAttribute]s. - /// No longer expands nested attributes. - factory StyleMixData.create(Iterable attributes) { - final variantList = []; - final contextVariantList = []; - final attributeList = []; - final decoratorList = []; - - for (final attribute in attributes) { - if (attribute is StyledWidgetAttributes) { - attributeList.add(attribute); - } else if (attribute is WidgetDecorator) { - decoratorList.add(attribute); - } else if (attribute is VariantAttribute) { - // Breakdown different types of variant attributes - if (attribute is ContextVariantAttribute) { - contextVariantList.add(attribute); - } else { - variantList.add(attribute); - } - } - } - - return StyleMixData( - attributes: MergeableMap(attributeList), - decorators: MergeableMap(decoratorList), - variants: variantList, - contextVariants: contextVariantList, - ); - } - - bool get hasVariants => variants.isNotEmpty; - - bool get hasContextVariants => contextVariants.isNotEmpty; - - bool get hasAttributes => attributes?.isNotEmpty == true; - - bool get isEmpty => !hasVariants && !hasContextVariants && !hasAttributes; - - bool get isNotEmpty => !isEmpty; - - int get length { - return variants.length + contextVariants.length + (attributes?.length ?? 0); - } - - /// Returns an instance of the specified [StyledWidgetAttributes] type from the [MixData]. - A? attributesOfType() { - return attributes?[A] as A?; - } - - /// Returns an [Iterable] of [StyleAttribute]s containing all attributes, variants, and directives. - Iterable toAttributes() { - return [ - ...?attributes?.values, - ...variants, - ...contextVariants, - ]; - } - - /// Creates a new [StyleMixData] instance by replacing the specified attributes with new values. - StyleMixData copyWith({ - MergeableMap? attributes, - MergeableMap? decorators, - List? variants, - List? contextVariants, - }) { - return StyleMixData( - attributes: this.attributes?.merge(attributes) ?? attributes, - decorators: this.decorators?.merge(decorators) ?? decorators, - variants: [...this.variants, ...?variants], - contextVariants: [...this.contextVariants, ...?contextVariants], - ); - } - - /// Merges the current [StyleMixData] instance with another [StyleMixData] instance. - StyleMixData merge(StyleMixData? other) { - if (other == null || other.isEmpty) return this; - - return copyWith( - attributes: other.attributes, - decorators: other.decorators, - variants: other.variants, - contextVariants: other.contextVariants, - ); - } - - /// Creates a new [StyleMixData] instance with the same attributes, variants, and directives. - StyleMixData clone() { - return StyleMixData( - attributes: attributes?.clone(), - decorators: decorators?.clone(), - variants: [...variants], - contextVariants: [...contextVariants], - ); - } - - /// An empty [StyleMixData] instance with no attributes, decorators, variants, or directives. - const StyleMixData.empty() - : attributes = null, - decorators = null, - variants = const [], - contextVariants = const []; - - @override - get props => [attributes, decorators, variants, contextVariants]; -} diff --git a/lib/src/helpers/color_helpers.dart b/lib/src/helpers/color_helpers.dart deleted file mode 100644 index 17e960bfd..000000000 --- a/lib/src/helpers/color_helpers.dart +++ /dev/null @@ -1,84 +0,0 @@ -import 'package:flutter/material.dart'; - -enum ColorSchemeNames { - primary, - primaryVariant, - secondary, - tertiary, - secondaryVariant, - surface, - background, - error, - onPrimary, - onSecondary, - onTertiary, - onSurface, - onBackground, - onError, -} - -extension ColorSchemeNamesExtension on ColorSchemeNames { - Color get value { - final colorIndex = _colorSchemeTranslationValues[index]; - - return colorIndex; - } -} - -const _colorSchemeTranslationValues = [ - Color(0xFF000001), - Color(0xFF000002), - Color(0xFF000003), - Color(0xFF000004), - Color(0xFF000005), - Color(0xFF000006), - Color(0xFF000007), - Color(0xFF000008), - Color(0xFF000009), - Color(0xFF00000A), - Color(0xFF00000B), - Color(0xFF00000C), -]; - -extension ColorExt on Color { - Color darken([double amount = .1]) { - assert(amount >= 0 && amount <= 1); - - final hsl = HSLColor.fromColor(this); - final hslDark = hsl.withLightness((hsl.lightness - amount).clamp(0.0, 1.0)); - - return hslDark.toColor(); - } - - Color lighten([double amount = .1]) { - assert(amount >= 0 && amount <= 1); - - final hsl = HSLColor.fromColor(this); - final hslLight = - hsl.withLightness((hsl.lightness + amount).clamp(0.0, 1.0)); - - return hslLight.toColor(); - } - - /// String is in the format "aabbcc" or "ffaabbcc" with an optional leading "#". - static Color fromHex(String hexString) => hexToColor(hexString); - - /// Prefixes a hash sign if [leadingHashSign] is set to `true` (default is `true`). - String toHex({bool leadingHashSign = true}) => '${leadingHashSign ? '#' : ''}' - '${alpha.toRadixString(16).padLeft(2, '0')}' - '${red.toRadixString(16).padLeft(2, '0')}' - '${green.toRadixString(16).padLeft(2, '0')}' - '${blue.toRadixString(16).padLeft(2, '0')}'; -} - -/// String is in the format "aabbcc" or "ffaabbcc" with an optional leading "#". - -Color hexToColor(String hexString) { - final buffer = StringBuffer(); - if (hexString.length == 6 || hexString.length == 7) buffer.write('ff'); - buffer.write(hexString.replaceFirst('#', '')); - - return Color( - int.parse(buffer.toString(), radix: 16), - ); -} diff --git a/lib/src/helpers/equality_mixin/deep_collection_equality.dart b/lib/src/helpers/equality_mixin/deep_collection_equality.dart deleted file mode 100644 index da8d6fb2f..000000000 --- a/lib/src/helpers/equality_mixin/deep_collection_equality.dart +++ /dev/null @@ -1,118 +0,0 @@ -/// A class to perform deep equality checks on collections. -/// -/// This class compares collections (List, Set, Map) recursively for equality. -/// It can also compute a hash code for a collection. -class DeepCollectionEquality { - /// Constructs a DeepCollectionEquality instance. - const DeepCollectionEquality(); - - /// Compares [object1] and [object2] deeply for equality. - /// - /// Returns true if both objects are deeply equal; otherwise, returns false. - bool equals(Object? object1, Object? object2) { - if (identical(object1, object2)) { - return true; - } - if (object1 is List && object2 is List) { - return _compareLists(object1, object2); - } - if (object1 is Set && object2 is Set) { - return _compareSets(object1, object2); - } - if (object1 is Map && object2 is Map) { - return _compareMaps(object1, object2); - } - - // Equality comparison for custom classes - if (object1?.runtimeType == object2?.runtimeType) { - return object1 == object2; - } - - return false; - } - - /// Computes a hash code for [object]. - /// - /// If [object] is a collection (List, Set, Map), computes a hash code recursively. - /// Otherwise, returns the hash code of the object. - int hash(Object? object) { - if (object == null) { - return 0; - } - - var hashCode = 0; - if (object is List) { - for (var element in object) { - hashCode = 31 * hashCode + hash(element); - } - } else if (object is Set) { - for (var element in object) { - hashCode = 31 * hashCode + hash(element); - } - } else if (object is Map) { - for (var key in object.keys) { - hashCode = 31 * hashCode + hash(key); - hashCode = 31 * hashCode + hash(object[key]); - } - } else { - hashCode = object.hashCode; - } - - return hashCode; - } - - /// Compares two lists [list1] and [list2] deeply for equality. - /// - /// Returns true if both lists are deeply equal; otherwise, returns false. - bool _compareLists(List list1, List list2) { - if (list1.length != list2.length) { - return false; - } - for (var i = 0; i < list1.length; i++) { - if (!equals(list1[i], list2[i])) { - return false; - } - } - - return true; - } - - /// Compares two sets [set1] and [set2] deeply for equality. - /// - /// Returns true if both sets are deeply equal; otherwise, returns false. - bool _compareSets(Set set1, Set set2) { - if (set1.length != set2.length) { - return false; - } - for (var element1 in set1) { - bool isEqual = false; - for (var element2 in set2) { - if (equals(element1, element2)) { - isEqual = true; - break; - } - } - if (!isEqual) { - return false; - } - } - - return true; - } - - /// Compares two maps [map1] and [map2] deeply for equality. - /// - /// Returns true if both maps are deeply equal; otherwise, returns false. - bool _compareMaps(Map map1, Map map2) { - if (map1.length != map2.length) { - return false; - } - for (var key in map1.keys) { - if (!map2.containsKey(key) || !equals(map1[key], map2[key])) { - return false; - } - } - - return true; - } -} diff --git a/lib/src/helpers/exports.dart b/lib/src/helpers/exports.dart deleted file mode 100644 index 6b6fd6f51..000000000 --- a/lib/src/helpers/exports.dart +++ /dev/null @@ -1 +0,0 @@ -export 'color_helpers.dart'; diff --git a/lib/src/helpers/extensions/build_context_ext.dart b/lib/src/helpers/extensions/build_context_ext.dart new file mode 100644 index 000000000..efd41777d --- /dev/null +++ b/lib/src/helpers/extensions/build_context_ext.dart @@ -0,0 +1,44 @@ +import 'package:flutter/material.dart'; + +import '../../factory/mix_provider.dart'; +import '../../factory/mix_provider_data.dart'; +import '../../theme/mix_theme.dart'; + +extension BuildContextExt on BuildContext { + MixData? get mix => Mix.maybeOf(this); + + /// MEDIA QUERY EXTENSION METHODS + + /// Directionality of context. + TextDirection get directionality => Directionality.of(this); + + /// Orientation of the device. + Orientation get orientation => MediaQuery.orientationOf(this); + + /// Screen size. + Size get screenSize => MediaQuery.sizeOf(this); + + // Theme Context Extensions. + Brightness get brightness => Theme.of(this).brightness; + + /// Theme context helpers. + ThemeData get theme => Theme.of(this); + + /// Theme color scheme. + ColorScheme get colorScheme => theme.colorScheme; + + /// Theme text theme. + TextTheme get textTheme => theme.textTheme; + + /// Mix Theme Data. + MixThemeData get mixTheme => MixTheme.of(this); + + /// Check if brightness is Brightness.dark. + bool get isDarkMode => brightness == Brightness.dark; + + /// Is device in landscape mode. + bool get isLandscape => orientation == Orientation.landscape; + + /// Is device in portrait mode. + bool get isPortrait => orientation == Orientation.portrait; +} diff --git a/lib/src/helpers/extensions/iterable_ext.dart b/lib/src/helpers/extensions/iterable_ext.dart new file mode 100644 index 000000000..b3df3726a --- /dev/null +++ b/lib/src/helpers/extensions/iterable_ext.dart @@ -0,0 +1,20 @@ +extension IterableExt on Iterable { + T? get firstMaybeNull => isEmpty ? null : first; + + T? firstWhereOrNull(bool Function(T element) test) { + for (T element in this) { + if (test(element)) { + return element; + } + } + + return null; + } + + Iterable sorted([Comparator? compare]) { + List newList = List.of(this); + newList.sort(compare); + + return newList; + } +} diff --git a/lib/src/helpers/extensions/string_ext.dart b/lib/src/helpers/extensions/string_ext.dart new file mode 100644 index 000000000..9e56a9f44 --- /dev/null +++ b/lib/src/helpers/extensions/string_ext.dart @@ -0,0 +1,88 @@ +const _snakeCaseSeparator = '_'; +const _paramCaseSeparator = '-'; +const _spaceSeparator = ' '; + +final _upperAlphaRegex = RegExp(r'[_-\sA-Z]'); + +final _symbolSet = { + _snakeCaseSeparator, + _paramCaseSeparator, + _spaceSeparator, +}; + +extension StringExt on String { + List get words { + final sb = StringBuffer(); + final words = []; + final isAllCaps = toUpperCase() == this; + + for (int i = 0; i < length; i++) { + final char = this[i]; + final nextChar = i + 1 == length ? null : this[i + 1]; + + if (_symbolSet.contains(char)) { + continue; + } + + sb.write(char); + + final isEndOfWord = nextChar == null || + (_upperAlphaRegex.hasMatch(nextChar) && !isAllCaps) || + _symbolSet.contains(nextChar); + + if (isEndOfWord) { + words.add(sb.toString()); + sb.clear(); + } + } + + return words; + } + + bool get isUpperCase => toUpperCase() == this; + + bool get isLowerCase => toLowerCase() == this; + + String get camelCase { + final wordList = words.map((word) => word.capitalize).toList(); + if (wordList.isNotEmpty) { + wordList[0] = wordList.first.toLowerCase(); + } + + return wordList.join(); + } + + String get pascalCase => words.map((word) => word.capitalize).join(); + + String get capitalize { + if (isEmpty) return this; + final firstRune = runes.first; + final restRunes = runes.skip(1); + + return String.fromCharCode(firstRune).toUpperCase() + + restRunes.map((rune) => String.fromCharCode(rune).toLowerCase()).join(); + } + + String get constantCase => words.uppercase.join(_snakeCaseSeparator); + + String get snakeCase => words.lowercase.join(_snakeCaseSeparator); + + String get paramCase => words.lowercase.join(_paramCaseSeparator); + + String get titleCase => + words.map((word) => word.capitalize).join(_spaceSeparator); + + String get sentenceCase { + final wordList = [...words]; + if (wordList.isEmpty) return this; + + wordList[0] = wordList.first.capitalize; + + return wordList.join(_spaceSeparator); + } +} + +extension ListStringExt on List { + List get lowercase => map((e) => e.toLowerCase()).toList(); + List get uppercase => map((e) => e.toUpperCase()).toList(); +} diff --git a/lib/src/extensions/style_mix_ext.dart b/lib/src/helpers/extensions/style_mix_ext.dart similarity index 65% rename from lib/src/extensions/style_mix_ext.dart rename to lib/src/helpers/extensions/style_mix_ext.dart index e5800d0d3..db1cbe0fb 100644 --- a/lib/src/extensions/style_mix_ext.dart +++ b/lib/src/helpers/extensions/style_mix_ext.dart @@ -1,78 +1,68 @@ -// ignore: long-parameter-list // ignore_for_file: long-parameter-list import 'package:flutter/material.dart'; -import '../attributes/attribute.dart'; -import '../factory/style_mix.dart'; -import '../variants/variant.dart'; -import '../widgets/container/container.widget.dart'; -import '../widgets/flex/flex.widget.dart'; -import '../widgets/icon/icon.widget.dart'; -import '../widgets/text/text.widget.dart'; +import '../../attributes/attribute.dart'; +import '../../factory/style_mix.dart'; +import '../../widgets/container_widget.dart'; +import '../../widgets/flex_widget.dart'; +import '../../widgets/icon_widget.dart'; +import '../../widgets/text_widget.dart'; -extension StyleMixExt on StyleMix { +extension StyleMixExt on StyleMix { StyledContainer container({ - StyleMix? style, - Key? key, - bool inherit = false, - List? variants, required Widget child, + bool inherit = false, + Key? key, + StyleMix? style, }) { return StyledContainer( - style: mergeNullable(style), + style: merge(style), key: key, - variants: variants, inherit: inherit, child: child, ); } StyledContainer box({ - @Deprecated('Use the style parameter instead') StyleMix? mix, - StyleMix? style, - Key? key, - bool inherit = false, - List? variants, required Widget child, + bool inherit = false, + Key? key, + StyleMix? style, + @Deprecated('Use the style parameter instead') StyleMix? mix, }) { return container( - style: mergeNullable(style ?? mix), - key: key, - variants: variants, inherit: inherit, + key: key, + style: style ?? mix, child: child, ); } HBox hbox({ + required List children, + bool inherit = false, + Key? key, @Deprecated('Use the style parameter instead') StyleMix? mix, StyleMix? style, - Key? key, - bool inherit = false, - List? variants, - required List children, }) { return HBox( - style: mergeNullable(style ?? mix), + style: merge(style ?? mix), key: key, - variants: variants, inherit: inherit, children: children, ); } StyledRow row({ + required List children, + bool inherit = false, + Key? key, @Deprecated('Use the style parameter instead') StyleMix? mix, StyleMix? style, - Key? key, - bool inherit = false, - List? variants, - required List children, }) { return StyledRow( - style: mergeNullable(style ?? mix), + style: merge(style ?? mix), key: key, - variants: variants, inherit: inherit, children: children, ); @@ -80,52 +70,46 @@ extension StyleMixExt on StyleMix { StyledText text( String text, { - @Deprecated('Use the style parameter instead') StyleMix? mix, - StyleMix? style, - Key? key, bool inherit = false, - List? variants, + Key? key, + @Deprecated('Use the style parameter instead') StyleMix? mix, String? semanticsLabel, + StyleMix? style, }) { return StyledText( text, - style: mergeNullable(style ?? mix), + semanticsLabel: semanticsLabel, + style: merge(style ?? mix), key: key, inherit: inherit, - variants: variants, - semanticsLabel: semanticsLabel, ); } VBox vbox({ + required List children, + bool inherit = false, + Key? key, @Deprecated('Use the style parameter instead') StyleMix? mix, StyleMix? style, - Key? key, - bool inherit = false, - List? variants, - required List children, }) { return VBox( - style: mergeNullable(style ?? mix), + style: merge(style ?? mix), key: key, - variants: variants, inherit: inherit, children: children, ); } StyledColumn column({ + required List children, + bool inherit = false, + Key? key, @Deprecated('Use the style parameter instead') StyleMix? mix, StyleMix? style, - Key? key, - bool inherit = false, - List? variants, - required List children, }) { return StyledColumn( - style: mergeNullable(style ?? mix), + style: merge(style ?? mix), key: key, - variants: variants, inherit: inherit, children: children, ); @@ -133,18 +117,16 @@ extension StyleMixExt on StyleMix { StyledIcon icon( IconData icon, { + bool inherit = false, + Key? key, @Deprecated('Use the style parameter instead') StyleMix? mix, StyleMix? style, - Key? key, - bool inherit = false, - List? variants, }) { return StyledIcon( icon, - style: mergeNullable(style ?? mix), + style: merge(style ?? mix), key: key, inherit: inherit, - variants: variants, ); } } diff --git a/lib/src/helpers/extensions/values_ext.dart b/lib/src/helpers/extensions/values_ext.dart new file mode 100644 index 000000000..6335aaf0a --- /dev/null +++ b/lib/src/helpers/extensions/values_ext.dart @@ -0,0 +1,406 @@ +import 'package:flutter/material.dart'; + +import '../../attributes/alignment_attribute.dart'; +import '../../attributes/border/border_attribute.dart'; +import '../../attributes/border/border_radius_attribute.dart'; +import '../../attributes/color_attribute.dart'; +import '../../attributes/constraints_attribute.dart'; +import '../../attributes/decoration_attribute.dart'; +import '../../attributes/edge_insets_attribute.dart'; +import '../../attributes/scalar_attribute.dart'; +import '../../attributes/shadow_attribute.dart'; +import '../../attributes/space_attribute.dart'; +import '../../attributes/strut_style_attribute.dart'; +import '../../attributes/text_style_attribute.dart'; + +extension StrutStyleExt on StrutStyle { + StrutStyleAttribute toAttribute() { + return StrutStyleAttribute( + fontFamily: fontFamily, + fontFamilyFallback: fontFamilyFallback, + fontSize: fontSize, + fontWeight: fontWeight, + fontStyle: fontStyle, + height: height, + leading: leading, + forceStrutHeight: forceStrutHeight, + ); + } + + StrutStyle merge(StrutStyle? other) { + return StrutStyle( + fontFamily: other?.fontFamily ?? fontFamily, + fontFamilyFallback: other?.fontFamilyFallback ?? fontFamilyFallback, + fontSize: other?.fontSize ?? fontSize, + height: other?.height ?? height, + leadingDistribution: other?.leadingDistribution ?? leadingDistribution, + leading: other?.leading ?? leading, + fontWeight: other?.fontWeight ?? fontWeight, + fontStyle: other?.fontStyle ?? fontStyle, + forceStrutHeight: other?.forceStrutHeight ?? forceStrutHeight, + debugLabel: other?.debugLabel ?? debugLabel, + ); + } +} + +// Extension for TextAlign +extension TextAlignExt on TextAlign { + TextAlignAttribute toAttribute() => TextAlignAttribute(this); +} + +extension GradientExt on Gradient { + GradientAttribute toAttribute() => GradientAttribute(this); +} + +extension EdgeInsetsGeometryExt on EdgeInsetsGeometry { + EdgeInsetsGeometryAttribute toAttribute() { + if (this is EdgeInsets) return (this as EdgeInsets).toAttribute(); + if (this is EdgeInsetsDirectional) { + return (this as EdgeInsetsDirectional).toAttribute(); + } + + throw UnimplementedError(); + } + + PaddingGeometryAttribute toPadding() { + if (this is EdgeInsets) return (this as EdgeInsets).toPadding(); + if (this is EdgeInsetsDirectional) { + return (this as EdgeInsetsDirectional).toPadding(); + } + + throw UnimplementedError(); + } + + MarginGeometryAttribute toMargin() { + if (this is EdgeInsets) return (this as EdgeInsets).toMargin(); + if (this is EdgeInsetsDirectional) { + return (this as EdgeInsetsDirectional).toMargin(); + } + + throw UnimplementedError(); + } +} + +extension EdgeInsetsExt on EdgeInsets { + EdgeInsetsAttribute toAttribute() => EdgeInsetsAttribute( + top: top, + bottom: bottom, + left: left, + right: right, + ); + + PaddingAttribute toPadding() => PaddingAttribute( + top: top, + bottom: bottom, + left: left, + right: right, + ); + + MarginAttribute toMargin() => MarginAttribute( + top: top, + bottom: bottom, + left: left, + right: right, + ); +} + +extension EdgeInsetsDirectionalExt on EdgeInsetsDirectional { + EdgeInsetsDirectionalAttribute toAttribute() => + EdgeInsetsDirectionalAttribute( + top: top, + bottom: bottom, + start: start, + end: end, + ); + + PaddingDirectionalAttribute toPadding() => PaddingDirectionalAttribute( + top: top, + bottom: bottom, + start: start, + end: end, + ); + + MarginDirectionalAttribute toMargin() => MarginDirectionalAttribute( + top: top, + bottom: bottom, + start: start, + end: end, + ); +} + +extension ColorExt on Color { + Color darken([double amount = 0.1]) { + assert(amount >= 0 && amount <= 1); + + final hsl = HSLColor.fromColor(this); + final hslDark = hsl.withLightness((hsl.lightness - amount).clamp(0.0, 1.0)); + + return hslDark.toColor(); + } + + Color lighten([double amount = 0.1]) { + assert(amount >= 0 && amount <= 1); + + final hsl = HSLColor.fromColor(this); + final hslLight = + hsl.withLightness((hsl.lightness + amount).clamp(0.0, 1.0)); + + return hslLight.toColor(); + } + + /// String is in the format "aabbcc" or "ffaabbcc" with an optional leading "#". + static Color fromHex(String hexString) { + String updatedHexString = hexString.replaceFirst('#', ''); + if (updatedHexString.length == 6) updatedHexString = 'ff$updatedHexString'; + + return Color(int.parse(updatedHexString, radix: 16)); + } + + /// Prefixes a hash sign if [leadingHashSign] is set to `true` (default is `true`). + String toHex({bool leadingHashSign = true}) => '${leadingHashSign ? '#' : ''}' + '${alpha.toRadixString(16).padLeft(2, '0')}' + '${red.toRadixString(16).padLeft(2, '0')}' + '${green.toRadixString(16).padLeft(2, '0')}' + '${blue.toRadixString(16).padLeft(2, '0')}'; + + ColorAttribute toAttribute() => ColorAttribute(this); +} + +// Extension for Alignment +extension AlignmentGeometryExt on AlignmentGeometry { + AlignmentGeometryAttribute toAttribute() { + if (this is Alignment) return (this as Alignment).toAttribute(); + if (this is AlignmentDirectional) { + return (this as AlignmentDirectional).toAttribute(); + } + throw UnimplementedError(); + } +} + +extension ShapeDecorationExt on ShapeDecoration { + ShapeDecorationAttribute toAttribute() => ShapeDecorationAttribute( + color: color?.toAttribute(), + shape: shape, + gradient: gradient?.toAttribute(), + boxShadow: shadows?.map((e) => e.toAttribute()).toList(), + ); +} + +extension AlignmentExt on Alignment { + AlignmentAttribute toAttribute() => AlignmentAttribute(x: x, y: y); +} + +extension AligmentDirectionalExt on AlignmentDirectional { + AlignmentDirectionalAttribute toAttribute() => + AlignmentDirectionalAttribute(start: start, y: y); +} + +extension BoxConstraintsExt on BoxConstraints { + BoxConstraintsAttribute toAttribute() => BoxConstraintsAttribute( + minWidth: minWidth, + maxWidth: maxWidth, + minHeight: minHeight, + maxHeight: maxHeight, + ); +} + +// Extension for MainAxisAlignment +extension MainAxisAlignmentExt on MainAxisAlignment { + MainAxisAlignmentAttribute toAttribute() => MainAxisAlignmentAttribute(this); +} + +// Extension for CrossAxisAlignment +extension CrossAxisAlignmentExt on CrossAxisAlignment { + CrossAxisAlignmentAttribute toAttribute() => + CrossAxisAlignmentAttribute(this); +} + +extension MainAxisSizeExt on MainAxisSize { + MainAxisSizeAttribute toAttribute() => MainAxisSizeAttribute(this); +} + +extension TextOverflowExt on TextOverflow { + TextOverflowAttribute toAttribute() => TextOverflowAttribute(this); +} + +extension VerticalDirectionExt on VerticalDirection { + VerticalDirectionAttribute toAttribute() => VerticalDirectionAttribute(this); +} + +extension ClipExt on Clip { + ClipAttribute toAttribute() => ClipAttribute(this); +} + +extension TextWidthBasisExt on TextWidthBasis { + TextWidthBasisAttribute toAttribute() => TextWidthBasisAttribute(this); +} + +extension TextHeightBehaviorExt on TextHeightBehavior { + TextHeightBehaviorAttribute toAttribute() => + TextHeightBehaviorAttribute(this); +} + +// Extension for TextDirection +extension TextDirectionExt on TextDirection { + TextDirectionAttribute toAttribute() => TextDirectionAttribute(this); +} + +extension ImageRepeatExt on ImageRepeat { + ImageRepeatAttribute toAttribute() => ImageRepeatAttribute(this); +} + +// Extension for Axis +extension AxisExt on Axis { + AxisAttribute toAttribute() => AxisAttribute(this); +} + +// Extension for BlendMode +extension BlendModeExt on BlendMode { + BlendModeAttribute toAttribute() => BlendModeAttribute(this); +} + +// Extension for BoxFit +extension BoxFitExt on BoxFit { + BoxFitAttribute toAttribute() => BoxFitAttribute(this); +} + +extension BoxDecorationExt on BoxDecoration { + BoxDecorationAttribute toAttribute() => BoxDecorationAttribute( + border: border?.toAttribute(), + borderRadius: borderRadius?.toAttribute(), + gradient: gradient?.toAttribute(), + boxShadow: boxShadow?.map((e) => e.toAttribute()).toList(), + color: color?.toAttribute(), + shape: shape.toAttribute(), + ); +} + +extension BoxShapeExt on BoxShape { + BoxShapeAttribute toAttribute() => BoxShapeAttribute(this); +} + +extension BorderRadiusGeometryExt on BorderRadiusGeometry { + BorderRadiusGeometryAttribute toAttribute() { + if (this is BorderRadius) return (this as BorderRadius).toAttribute(); + if (this is BorderRadiusDirectional) { + return (this as BorderRadiusDirectional).toAttribute(); + } + + throw UnimplementedError(); + } +} + +extension BorderRadiusDirectionalExrt on BorderRadiusDirectional { + BorderRadiusDirectionalAttribute toAttribute() => + BorderRadiusDirectionalAttribute( + topStart: topStart, + topEnd: topEnd, + bottomStart: bottomStart, + bottomEnd: bottomEnd, + ); +} + +// Extension for BorderRadius +extension BorderRadiusExt on BorderRadius { + BorderRadiusAttribute toAttribute() => BorderRadiusAttribute( + topLeft: topLeft, + topRight: topRight, + bottomLeft: bottomLeft, + bottomRight: bottomRight, + ); +} + +extension TextBaseLineExt on TextBaseline { + TextBaselineAttribute toAttribute() => TextBaselineAttribute(this); +} + +extension Matrix4Ext on Matrix4 { + TransformAttribute toAttribute() => TransformAttribute(this); + + /// Merge [other] into this matrix. + Matrix4 merge(Matrix4? other) { + if (other == null || other == this) return this; + + return clone()..multiply(other); + } +} + +extension BorderSideExt on BorderSide { + BorderSideAttribute toAttribute() => BorderSideAttribute( + color: color.toAttribute(), + strokeAlign: strokeAlign, + style: style, + width: width, + ); +} + +extension BoxBorderExt on BoxBorder { + BoxBorderAttribute toAttribute() { + if (this is Border) return (this as Border).toAttribute(); + if (this is BorderDirectional) { + return (this as BorderDirectional).toAttribute(); + } + + throw UnimplementedError(); + } +} + +extension ShadowExt on Shadow { + ShadowAttribute toAttribute() => ShadowAttribute( + blurRadius: blurRadius, + color: color.toAttribute(), + offset: offset, + ); +} + +extension BoxShadowExt on BoxShadow { + BoxShadowAttribute toAttribute() => BoxShadowAttribute( + color: color.toAttribute(), + offset: offset, + blurRadius: blurRadius, + spreadRadius: spreadRadius, + ); +} + +extension TextStyleExt on TextStyle { + TextStyleAttribute toAttribute() => TextStyleAttribute( + background: background, + color: color?.toAttribute(), + debugLabel: debugLabel, + decoration: decoration, + decorationColor: decorationColor?.toAttribute(), + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fontFamily: fontFamily, + fontFamilyFallback: fontFamilyFallback, + fontFeatures: fontFeatures, + fontSize: fontSize, + fontStyle: fontStyle, + fontWeight: fontWeight, + foreground: foreground, + height: height, + letterSpacing: letterSpacing, + locale: locale, + shadows: shadows?.map((e) => e.toAttribute()).toList(), + textBaseline: textBaseline, + wordSpacing: wordSpacing, + ); +} + +extension BorderExt on Border { + BorderAttribute toAttribute() => BorderAttribute( + left: left.toAttribute(), + right: right.toAttribute(), + top: top.toAttribute(), + bottom: bottom.toAttribute(), + ); +} + +extension BorderDirectionalExt on BorderDirectional { + BorderDirectionalAttribute toAttribute() => BorderDirectionalAttribute( + start: start.toAttribute(), + end: end.toAttribute(), + top: top.toAttribute(), + bottom: bottom.toAttribute(), + ); +} diff --git a/lib/src/helpers/logger.dart b/lib/src/helpers/logger.dart deleted file mode 100644 index bd0f98460..000000000 --- a/lib/src/helpers/logger.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'package:flutter/foundation.dart'; - -class Logger { - Logger(this.tag); - - final String tag; - final Stopwatch stopwatch = Stopwatch(); - - void start() { - stopwatch.start(); - } - - void stop() { - stopwatch.stop(); - debugPrint('$tag: ${stopwatch.elapsedMicroseconds} microseconds'); - } - - void debug(String message) { - debugPrint('$tag: $message'); - } -} diff --git a/lib/src/helpers/mergeable_list.dart b/lib/src/helpers/mergeable_list.dart deleted file mode 100644 index 8ba40f458..000000000 --- a/lib/src/helpers/mergeable_list.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'dart:math'; - -import 'package:flutter/foundation.dart'; - -import '../attributes/attribute.dart'; - -List combineMergeableLists( - List list, - List? other, -) { - if (other == null || listEquals(other, list)) return list; - - final maxLength = max(list.length, other.length); - - return List.generate(maxLength, (int index) { - final otherValue = index < other.length ? other[index] : null; - final thisValue = index < list.length ? list[index] : null; - - return thisValue?.merge(otherValue) ?? otherValue!; - }); -} diff --git a/lib/src/helpers/mergeable_map.dart b/lib/src/helpers/mergeable_map.dart deleted file mode 100644 index c2de81a04..000000000 --- a/lib/src/helpers/mergeable_map.dart +++ /dev/null @@ -1,123 +0,0 @@ -import 'dart:collection'; - -import '../attributes/attribute.dart'; - -/// A map-like data structure that can merge values with the same key based on -/// their runtime type. Maintains insertion order of keys. -/// -/// This is used to merge different attributes. -class MergeableMap { - final LinkedHashMap _map = LinkedHashMap(); - - /// Creates a new [MergeableMap] instance with the given [iterable]. - /// - /// The optional [keyMapper] function is used to map the iterable items to - /// their respective keys. If not provided, the runtime type of the item is - /// used as the key. - MergeableMap(List iterable) { - for (final item in iterable) { - _update(item); - } - } - - /// Creates an empty [MergeableMap] instance. - factory MergeableMap.empty() { - return MergeableMap([]); - } - - void _update(T value) { - _map.update( - value.runtimeType, - (existingValue) => existingValue.merge(value), - ifAbsent: () => value, - ); - } - - /// Retrieves the value associated with the given [key] or `null` if not found. - T? operator [](Type key) => _map[key]; - - /// Associates the [value] with the given [key]. If the key already exists, - /// the value is merged with the existing value. - void operator []=(Type key, covariant T value) { - _update(value); - } - - /// Merges this [MergeableMap] with another [MergeableMap] and returns a new - /// [MergeableMap] containing the merged elements. - /// - /// If the `other` map is `null`, it returns a new [MergeableMap] that is - /// identical to the current map. If the `other` map is not `null`, it - /// iterates over the keys of both maps and creates a new [MergeableMap] - /// containing the union of both maps. In case of overlapping keys, the value - /// from the `other` map will overwrite the value from the current map. - MergeableMap merge(MergeableMap? other) { - if (other == null) return this; - - final mergedMap = MergeableMap.empty(); - mergedMap._map.addAll(_map); - other._map.forEach((key, value) { - mergedMap[key] = value; - }); - - return mergedMap; - } - - /// Creates a new [MergeableMap] instance with the same key-value pairs as - /// this map. - MergeableMap clone() { - final clonedMap = MergeableMap.empty(); - clonedMap._map.addAll(_map); - - return clonedMap; - } - - /// Returns an [Iterable] of the values in the map in insertion order. - Iterable get values => _map.values; - - /// Returns the number of key-value pairs in the map. - int get length => _map.length; - - /// Removes all key-value pairs from the map. - void clear() { - _map.clear(); - } - - T firstWhere(bool Function(T) test) { - return _map.values.firstWhere(test); - } - - /// Returns `true` if the map contains no key-value pairs. - bool get isEmpty => _map.isEmpty; - - /// Returns `true` if the map contains at least one key-value pair. - - bool get isNotEmpty => _map.isNotEmpty; - - /// Determines the equality of two [MergeableMap] instances. - /// - /// Returns true if both instances have the same key-value pairs and - /// insertion order. - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - - if (other is MergeableMap) { - if (other._map.length != _map.length) return false; - - for (final key in _map.keys) { - if (!other._map.containsKey(key) || _map[key] != other._map[key]) { - return false; - } - } - - return true; - } - - return false; - } - - /// Generates the hash code for this [MergeableMap] instance based on its - /// key-value pairs. - @override - int get hashCode => _map.hashCode; -} diff --git a/lib/src/specs/container_spec.dart b/lib/src/specs/container_spec.dart new file mode 100644 index 000000000..05adf4b05 --- /dev/null +++ b/lib/src/specs/container_spec.dart @@ -0,0 +1,89 @@ +import 'package:flutter/material.dart'; + +import '../attributes/alignment_attribute.dart'; +import '../attributes/attribute.dart'; +import '../attributes/constraints_attribute.dart'; +import '../attributes/decoration_attribute.dart'; +import '../attributes/scalar_attribute.dart'; +import '../attributes/space_attribute.dart'; +import '../factory/mix_provider_data.dart'; + +class ContainerSpec extends MixExtension { + final AlignmentGeometry? alignment; + final EdgeInsetsGeometry? padding; + final EdgeInsetsGeometry? margin; + final BoxConstraints? constraints; + final Decoration? decoration; + + final Matrix4? transform; + final Clip? clipBehavior; + + const ContainerSpec({ + required this.alignment, + required this.padding, + required this.margin, + required this.constraints, + required this.decoration, + required this.transform, + required this.clipBehavior, + }); + + static ContainerSpec resolve(MixData mix) { + return ContainerSpec( + alignment: mix.get(), + padding: mix.get(), + margin: mix.get(), + constraints: mix.get(), + decoration: mix.get(), + transform: mix.get(), + clipBehavior: mix.get(), + ); + } + + @override + ContainerSpec copyWith({ + AlignmentGeometry? alignment, + EdgeInsetsGeometry? padding, + EdgeInsetsGeometry? margin, + BoxConstraints? constraints, + Decoration? decoration, + double? width, + double? height, + Matrix4? transform, + Clip? clipBehavior, + }) { + return ContainerSpec( + alignment: alignment ?? this.alignment, + padding: padding ?? this.padding, + margin: margin ?? this.margin, + constraints: constraints ?? this.constraints, + decoration: decoration ?? this.decoration, + transform: transform ?? this.transform, + clipBehavior: clipBehavior ?? this.clipBehavior, + ); + } + + @override + ContainerSpec lerp(ContainerSpec other, double t) { + return ContainerSpec( + alignment: AlignmentGeometry.lerp(alignment, other.alignment, t), + padding: EdgeInsetsGeometry.lerp(padding, other.padding, t), + margin: EdgeInsetsGeometry.lerp(margin, other.margin, t), + constraints: BoxConstraints.lerp(constraints, other.constraints, t), + decoration: Decoration.lerp(decoration, other.decoration, t), + transform: Matrix4Tween(begin: transform, end: other.transform).lerp(t), + clipBehavior: t < 0.5 ? clipBehavior : other.clipBehavior, + ); + } + + @override + get props => [ + alignment, + padding, + margin, + constraints, + decoration, + transform, + clipBehavior, + ]; +} diff --git a/lib/src/specs/flex_spec.dart b/lib/src/specs/flex_spec.dart new file mode 100644 index 000000000..c994b34c3 --- /dev/null +++ b/lib/src/specs/flex_spec.dart @@ -0,0 +1,92 @@ +import 'package:flutter/material.dart'; + +import '../attributes/attribute.dart'; +import '../attributes/scalar_attribute.dart'; +import '../factory/mix_provider_data.dart'; + +class FlexSpec extends MixExtension { + final Axis? direction; + final MainAxisAlignment? mainAxisAlignment; + final CrossAxisAlignment? crossAxisAlignment; + final MainAxisSize? mainAxisSize; + final VerticalDirection? verticalDirection; + final TextDirection? textDirection; + final TextBaseline? textBaseline; + final Clip? clipBehavior; + + const FlexSpec({ + required this.crossAxisAlignment, + required this.mainAxisAlignment, + required this.mainAxisSize, + required this.verticalDirection, + required this.direction, + required this.textDirection, + required this.textBaseline, + required this.clipBehavior, + }); + + static FlexSpec resolve(MixData mix) { + return FlexSpec( + crossAxisAlignment: + mix.get(), + mainAxisAlignment: + mix.get(), + mainAxisSize: mix.get(), + verticalDirection: + mix.get(), + direction: mix.get(), + textDirection: mix.get(), + textBaseline: mix.get(), + clipBehavior: mix.get(), + ); + } + + @override + FlexSpec lerp(FlexSpec other, double t) { + return FlexSpec( + crossAxisAlignment: snap(crossAxisAlignment, other.crossAxisAlignment, t), + mainAxisAlignment: snap(mainAxisAlignment, other.mainAxisAlignment, t), + mainAxisSize: snap(mainAxisSize, other.mainAxisSize, t), + verticalDirection: snap(verticalDirection, other.verticalDirection, t), + direction: snap(direction, other.direction, t), + textDirection: snap(textDirection, other.textDirection, t), + textBaseline: snap(textBaseline, other.textBaseline, t), + clipBehavior: snap(clipBehavior, other.clipBehavior, t), + ); + } + + @override + FlexSpec copyWith({ + Axis? direction, + MainAxisAlignment? mainAxisAlignment, + CrossAxisAlignment? crossAxisAlignment, + MainAxisSize? mainAxisSize, + VerticalDirection? verticalDirection, + TextDirection? textDirection, + TextBaseline? textBaseline, + Clip? clipBehavior, + }) { + return FlexSpec( + crossAxisAlignment: crossAxisAlignment ?? this.crossAxisAlignment, + mainAxisAlignment: mainAxisAlignment ?? this.mainAxisAlignment, + mainAxisSize: mainAxisSize ?? this.mainAxisSize, + verticalDirection: verticalDirection ?? this.verticalDirection, + direction: direction ?? this.direction, + textDirection: textDirection ?? this.textDirection, + textBaseline: textBaseline ?? this.textBaseline, + clipBehavior: clipBehavior ?? this.clipBehavior, + ); + } + + @override + List get props => [ + crossAxisAlignment, + mainAxisAlignment, + mainAxisSize, + verticalDirection, + direction, + textDirection, + textBaseline, + clipBehavior, + ]; +} diff --git a/lib/src/specs/icon_spec.dart b/lib/src/specs/icon_spec.dart new file mode 100644 index 000000000..889851048 --- /dev/null +++ b/lib/src/specs/icon_spec.dart @@ -0,0 +1,52 @@ +import 'dart:ui'; + +import '../attributes/attribute.dart'; +import '../attributes/color_attribute.dart'; +import '../attributes/scalar_attribute.dart'; +import '../factory/mix_provider_data.dart'; + +class IconSpec extends MixExtension { + final Color? color; + final double? size; + + final TextDirection? textDirection; + + const IconSpec({ + required this.color, + required this.size, + required this.textDirection, + }); + + static IconSpec resolve(MixData mix) { + return IconSpec( + color: mix.get(), + size: mix.get(), + textDirection: mix.get(), + ); + } + + @override + IconSpec lerp(IconSpec other, double t) { + return IconSpec( + color: Color.lerp(color, other.color, t), + size: lerpDouble(size, other.size, t), + textDirection: snap(textDirection, other.textDirection, t), + ); + } + + @override + IconSpec copyWith({ + Color? color, + double? size, + TextDirection? textDirection, + }) { + return IconSpec( + color: color ?? this.color, + size: size ?? this.size, + textDirection: textDirection ?? this.textDirection, + ); + } + + @override + get props => [color, size, textDirection]; +} diff --git a/lib/src/specs/image_spec.dart b/lib/src/specs/image_spec.dart new file mode 100644 index 000000000..1e9544320 --- /dev/null +++ b/lib/src/specs/image_spec.dart @@ -0,0 +1,67 @@ +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import '../attributes/attribute.dart'; +import '../attributes/color_attribute.dart'; +import '../attributes/scalar_attribute.dart'; +import '../factory/mix_provider_data.dart'; + +@immutable +class ImageSpec extends MixExtension { + final double? width, height; + final Color? color; + final ImageRepeat? repeat; + final BoxFit? fit; + + const ImageSpec({ + required this.width, + required this.height, + required this.color, + required this.repeat, + required this.fit, + }); + + static ImageSpec resolve(MixData mix) { + return ImageSpec( + width: mix.get(), + height: mix.get(), + color: mix.get(), + repeat: mix.get(), + fit: mix.get(), + ); + } + + @override + ImageSpec lerp(ImageSpec? other, double t) { + return ImageSpec( + width: lerpDouble(width, other?.width, t), + height: lerpDouble(height, other?.height, t), + color: Color.lerp(color, other?.color, t), + repeat: t < 0.5 ? repeat : other?.repeat, + fit: t < 0.5 ? fit : other?.fit, + ); + } + + @override + ImageSpec copyWith({ + ImageProvider? image, + double? width, + double? height, + Color? color, + ImageRepeat? repeat, + BoxFit? fit, + }) { + return ImageSpec( + width: width ?? this.width, + height: height ?? this.height, + color: color ?? this.color, + repeat: repeat ?? this.repeat, + fit: fit ?? this.fit, + ); + } + + @override + get props => [width, height, color, repeat, fit]; +} diff --git a/lib/src/specs/stack_spec.dart b/lib/src/specs/stack_spec.dart new file mode 100644 index 000000000..ee7f8af5d --- /dev/null +++ b/lib/src/specs/stack_spec.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +import '../attributes/alignment_attribute.dart'; +import '../attributes/attribute.dart'; +import '../attributes/scalar_attribute.dart'; +import '../factory/mix_provider_data.dart'; + +class StackSpec extends MixExtension { + final AlignmentGeometry? alignment; + final StackFit? fit; + final TextDirection? textDirection; + final Clip? clipBehavior; + + const StackSpec({ + this.alignment, + this.fit, + this.textDirection, + this.clipBehavior, + }); + + static StackSpec resolve(MixData mix) { + return StackSpec( + alignment: mix.get(), + fit: mix.get(), + textDirection: mix.get(), + clipBehavior: mix.get(), + ); + } + + @override + StackSpec lerp(StackSpec other, double t) { + return StackSpec( + alignment: AlignmentGeometry.lerp(alignment, other.alignment, t), + fit: t < 0.5 ? fit : other.fit, + textDirection: t < 0.5 ? textDirection : other.textDirection, + clipBehavior: t < 0.5 ? clipBehavior : other.clipBehavior, + ); + } + + @override + StackSpec copyWith({ + AlignmentGeometry? alignment, + StackFit? fit, + TextDirection? textDirection, + Clip? clipBehavior, + }) { + return StackSpec( + alignment: alignment ?? this.alignment, + fit: fit ?? this.fit, + textDirection: textDirection ?? this.textDirection, + clipBehavior: clipBehavior ?? this.clipBehavior, + ); + } + + @override + List get props => [alignment, fit, textDirection, clipBehavior]; +} diff --git a/lib/src/specs/text_spec.dart b/lib/src/specs/text_spec.dart new file mode 100644 index 000000000..f810cc012 --- /dev/null +++ b/lib/src/specs/text_spec.dart @@ -0,0 +1,128 @@ +import 'package:flutter/material.dart'; + +import '../attributes/attribute.dart'; +import '../attributes/scalar_attribute.dart'; +import '../attributes/strut_style_attribute.dart'; +import '../attributes/text_style_attribute.dart'; +import '../directives/text_directive.dart'; +import '../factory/mix_provider_data.dart'; + +class TextSpec extends MixExtension { + final TextOverflow? overflow; + final StrutStyle? strutStyle; + final TextAlign? textAlign; + final double? textScaleFactor; + final int? maxLines; + final TextWidthBasis? textWidthBasis; + final TextHeightBehavior? textHeightBehavior; + final TextStyle? style; + final TextDirection? textDirection; + final bool? softWrap; + + final List directives; + const TextSpec({ + required this.overflow, + this.strutStyle, + this.textAlign, + this.textScaleFactor, + this.maxLines, + this.style, + this.textWidthBasis, + this.textHeightBehavior, + this.textDirection, + this.softWrap, + this.directives = const [], + }); + + static TextSpec resolve(MixData mix) { + return TextSpec( + overflow: mix.get(), + strutStyle: mix.get(), + textAlign: mix.get(), + textScaleFactor: mix.get(), + maxLines: mix.get(), + style: mix.get(), + textWidthBasis: mix.get(), + textHeightBehavior: + mix.get(), + textDirection: mix.get(), + softWrap: mix.get(), + directives: mix.get>() ?? [], + ); + } + + String applyTextDirectives(String? text) { + if (text == null) return ''; + + String modifiedText = text; + for (final directive in directives) { + modifiedText = directive.modify(modifiedText); + } + + return modifiedText; + } + + @override + TextSpec lerp(TextSpec other, double t) { + // Define a helper method for snapping + + return TextSpec( + overflow: snap(overflow, other.overflow, t), + strutStyle: snap(strutStyle, other.strutStyle, t), + textAlign: snap(textAlign, other.textAlign, t), + textScaleFactor: + genericNumLerp(textScaleFactor, other.textScaleFactor, t), + maxLines: snap(maxLines, other.maxLines, t), + style: TextStyle.lerp(style, other.style, t), + textWidthBasis: snap(textWidthBasis, other.textWidthBasis, t), + textHeightBehavior: snap(textHeightBehavior, other.textHeightBehavior, t), + textDirection: snap(textDirection, other.textDirection, t), + softWrap: snap(softWrap, other.softWrap, t), + directives: snap(directives, other.directives, t), + ); + } + + @override + TextSpec copyWith({ + bool? softWrap, + TextOverflow? overflow, + StrutStyle? strutStyle, + TextAlign? textAlign, + double? textScaleFactor, + int? maxLines, + TextStyle? style, + TextWidthBasis? textWidthBasis, + TextHeightBehavior? textHeightBehavior, + List? directives, + TextDirection? textDirection, + }) { + return TextSpec( + overflow: overflow ?? this.overflow, + strutStyle: strutStyle ?? this.strutStyle, + textAlign: textAlign ?? this.textAlign, + textScaleFactor: textScaleFactor ?? this.textScaleFactor, + maxLines: maxLines ?? this.maxLines, + style: style ?? this.style, + textWidthBasis: textWidthBasis ?? this.textWidthBasis, + textHeightBehavior: textHeightBehavior ?? this.textHeightBehavior, + textDirection: textDirection ?? this.textDirection, + softWrap: softWrap ?? this.softWrap, + directives: directives ?? this.directives, + ); + } + + @override + List get props => [ + softWrap, + overflow, + strutStyle, + textAlign, + textScaleFactor, + maxLines, + textWidthBasis, + textHeightBehavior, + style, + directives, + textDirection, + ]; +} diff --git a/lib/src/theme/exports.dart b/lib/src/theme/exports.dart deleted file mode 100644 index 7cb8282eb..000000000 --- a/lib/src/theme/exports.dart +++ /dev/null @@ -1,7 +0,0 @@ -export 'material_theme/color_scheme_tokens.dart'; -export 'material_theme/material_tokens.dart'; -export 'material_theme/text_theme_tokens.dart'; -export 'mix_theme.dart'; -export 'tokens/color_token.dart'; -export 'tokens/space_token.dart'; -export 'tokens/text_style_token.dart'; diff --git a/lib/src/theme/material_theme/color_scheme_tokens.dart b/lib/src/theme/material_theme/color_scheme_tokens.dart deleted file mode 100644 index 6f4c2ba62..000000000 --- a/lib/src/theme/material_theme/color_scheme_tokens.dart +++ /dev/null @@ -1,52 +0,0 @@ -import '../../extensions/build_context_ext.dart'; -import '../tokens/color_token.dart'; - -class $MDColorScheme { - const $MDColorScheme._(); - - static const primary = ColorToken('primary'); - - static const secondary = ColorToken('secondary'); - - static const tertiary = ColorToken('tertiary'); - - static const surface = ColorToken('surface'); - - static const background = ColorToken('background'); - - static const error = ColorToken('error'); - - static const onPrimary = ColorToken('onPrimary'); - - static const onSecondary = ColorToken('onSecondary'); - - static const onTertiary = ColorToken('onTertiary'); - - static const onSurface = ColorToken('onSurface'); - - static const onBackground = ColorToken('onBackground'); - - static const onError = ColorToken('onError'); - - static MixColorTokens get tokens { - return { - primary: (context) => context.colorScheme.primary, - secondary: (context) => context.colorScheme.secondary, - tertiary: (context) => context.colorScheme.tertiary, - surface: (context) => context.colorScheme.surface, - background: (context) => context.colorScheme.background, - error: (context) => context.colorScheme.error, - onPrimary: (context) => context.colorScheme.onPrimary, - onSecondary: (context) => context.colorScheme.onSecondary, - onTertiary: (context) => context.colorScheme.onTertiary, - onSurface: (context) => context.colorScheme.onSurface, - onBackground: (context) => context.colorScheme.onBackground, - onError: (context) => context.colorScheme.onError, - }; - } -} - -// The same color scheme is compabile with Material 2. -// Added typedef just for consistency -typedef $M2Color = $MDColorScheme; -typedef $M3Color = $MDColorScheme; diff --git a/lib/src/theme/material_theme/material_tokens.dart b/lib/src/theme/material_theme/material_tokens.dart deleted file mode 100644 index ddeeb6ed9..000000000 --- a/lib/src/theme/material_theme/material_tokens.dart +++ /dev/null @@ -1,114 +0,0 @@ -import '../../../mix.dart'; - -@Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') -class MaterialTextThemeTokens { - const MaterialTextThemeTokens(); - - // Material 3 TextTheme Tokens - @Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') - final displayLarge = $M3Text.displayLarge; - @Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') - final displayMedium = $M3Text.displayMedium; - @Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') - final displaySmall = $M3Text.displaySmall; - @Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') - final headlineLarge = $M3Text.headlineLarge; - @Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') - final headlineMedium = $M3Text.headlineMedium; - @Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') - final headlineSmall = $M3Text.headlineSmall; - @Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') - final titleLarge = $M3Text.titleLarge; - @Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') - final titleMedium = $M3Text.titleMedium; - @Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') - final titleSmall = $M3Text.titleSmall; - @Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') - final bodyLarge = $M3Text.bodyLarge; - @Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') - final bodyMedium = $M3Text.bodyMedium; - @Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') - final bodySmall = $M3Text.bodySmall; - @Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') - final labelLarge = $M3Text.labelLarge; - @Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') - final labelMedium = $M3Text.labelMedium; - @Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') - final labelSmall = $M3Text.labelSmall; - - // Material 2 TextTheme Tokens - @Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') - final headline1 = $M2Text.headline1; - @Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') - final headline2 = $M2Text.headline2; - @Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') - final headline3 = $M2Text.headline3; - @Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') - final headline4 = $M2Text.headline4; - @Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') - final headline5 = $M2Text.headline5; - @Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') - final headline6 = $M2Text.headline6; - @Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') - final subtitle1 = $M2Text.subtitle1; - @Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') - final subtitle2 = $M2Text.subtitle2; - @Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') - final bodyText1 = $M2Text.bodyText1; - @Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') - final bodyText2 = $M2Text.bodyText2; - @Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') - final caption = $M2Text.caption; - @Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') - final button = $M2Text.button; - @Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') - final overline = $M2Text.overline; -} - -@Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') -class MaterialColorSchemeTokens { - const MaterialColorSchemeTokens(); - - @Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') - final primary = $MDColorScheme.primary; - - @Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') - final secondary = $MDColorScheme.secondary; - - @Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') - final tertiary = $MDColorScheme.tertiary; - - @Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') - final surface = $MDColorScheme.surface; - - @Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') - final background = $MDColorScheme.background; - - @Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') - final error = $MDColorScheme.error; - - @Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') - final onPrimary = $MDColorScheme.onPrimary; - - @Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') - final onSecondary = $MDColorScheme.onSecondary; - - @Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') - final onTertiary = $MDColorScheme.onTertiary; - - @Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') - final onSurface = $MDColorScheme.onSurface; - - @Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') - final onBackground = $MDColorScheme.onBackground; - - @Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') - final onError = $MDColorScheme.onError; -} - -@Deprecated('This has been deprecated now use MD3, and MD2 tokens instead') -class MaterialTokens { - const MaterialTokens._(); - static const textTheme = MaterialTextThemeTokens(); - static const colorScheme = MaterialColorSchemeTokens(); -} diff --git a/lib/src/theme/material_theme/text_theme_tokens.dart b/lib/src/theme/material_theme/text_theme_tokens.dart deleted file mode 100644 index a777e3366..000000000 --- a/lib/src/theme/material_theme/text_theme_tokens.dart +++ /dev/null @@ -1,83 +0,0 @@ -// ignore_for_file: deprecated_member_use - -import '../../extensions/build_context_ext.dart'; -import '../tokens/mix_token.dart'; -import '../tokens/text_style_token.dart'; - -// Material 3 TextTheme Tokens - -class $M3Text { - const $M3Text._(); - static const displayLarge = TextStyleToken('displayLarge'); - static const displayMedium = TextStyleToken('displayMedium'); - static const displaySmall = TextStyleToken('displaySmall'); - static const headlineLarge = TextStyleToken('headlineLarge'); - static const headlineMedium = TextStyleToken('headlineMedium'); - static const headlineSmall = TextStyleToken('headlineSmall'); - static const titleLarge = TextStyleToken('titleLarge'); - static const titleMedium = TextStyleToken('titleMedium'); - static const titleSmall = TextStyleToken('titleSmall'); - static const bodyLarge = TextStyleToken('bodyLarge'); - static const bodyMedium = TextStyleToken('bodyMedium'); - static const bodySmall = TextStyleToken('bodySmall'); - static const labelLarge = TextStyleToken('labelLarge'); - static const labelMedium = TextStyleToken('labelMedium'); - static const labelSmall = TextStyleToken('labelSmall'); - - static MixTextStyleTokens get tokens { - return { - displayLarge: (context) => context.textTheme.displayLarge, - displayMedium: (context) => context.textTheme.displayMedium, - displaySmall: (context) => context.textTheme.displaySmall, - headlineLarge: (context) => context.textTheme.headlineLarge, - headlineMedium: (context) => context.textTheme.headlineMedium, - headlineSmall: (context) => context.textTheme.headlineSmall, - titleLarge: (context) => context.textTheme.titleLarge, - titleMedium: (context) => context.textTheme.titleMedium, - titleSmall: (context) => context.textTheme.titleSmall, - bodyLarge: (context) => context.textTheme.bodyLarge, - bodyMedium: (context) => context.textTheme.bodyMedium, - bodySmall: (context) => context.textTheme.bodySmall, - labelLarge: (context) => context.textTheme.labelLarge, - labelMedium: (context) => context.textTheme.labelMedium, - labelSmall: (context) => context.textTheme.labelSmall, - }; - } -} - -// Material 2 TextTheme Tokens -class $M2Text { - const $M2Text._(); - - static const headline1 = TextStyleToken('headline1'); - static const headline2 = TextStyleToken('headline2'); - static const headline3 = TextStyleToken('headline3'); - static const headline4 = TextStyleToken('headline4'); - static const headline5 = TextStyleToken('headline5'); - static const headline6 = TextStyleToken('headline6'); - static const subtitle1 = TextStyleToken('subtitle1'); - static const subtitle2 = TextStyleToken('subtitle2'); - static const bodyText1 = TextStyleToken('bodyText1'); - static const bodyText2 = TextStyleToken('bodyText2'); - static const caption = TextStyleToken('caption'); - static const button = TextStyleToken('button'); - static const overline = TextStyleToken('overline'); - - static MixTextStyleTokens get tokens { - return { - headline1: (context) => context.textTheme.headline1, - headline2: (context) => context.textTheme.headline2, - headline3: (context) => context.textTheme.headline3, - headline4: (context) => context.textTheme.headline4, - headline5: (context) => context.textTheme.headline5, - headline6: (context) => context.textTheme.headline6, - subtitle1: (context) => context.textTheme.subtitle1, - subtitle2: (context) => context.textTheme.subtitle2, - bodyText1: (context) => context.textTheme.bodyText1, - bodyText2: (context) => context.textTheme.bodyText2, - caption: (context) => context.textTheme.caption, - button: (context) => context.textTheme.button, - overline: (context) => context.textTheme.overline, - }; - } -} diff --git a/lib/src/theme/mix_theme.dart b/lib/src/theme/mix_theme.dart index f303dedf2..8adc7b3fb 100644 --- a/lib/src/theme/mix_theme.dart +++ b/lib/src/theme/mix_theme.dart @@ -1,20 +1,17 @@ import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; -import '../../mix.dart'; -import '../helpers/equality_mixin/equality_mixin.dart'; +import '../core/equality/compare_mixin.dart'; +import '../helpers/extensions/iterable_ext.dart'; import 'tokens/breakpoints.dart'; +import 'tokens/color_token.dart'; import 'tokens/mix_token.dart'; -import 'tokens/radii_token.dart'; +import 'tokens/radius_token.dart'; +import 'tokens/space_token.dart'; +import 'tokens/text_style_token.dart'; class MixTheme extends InheritedWidget { - const MixTheme({ - Key? key, - required Widget child, - required this.data, - }) : super(key: key, child: child); - - final MixThemeData data; + const MixTheme({required Widget child, required this.data, Key? key}) + : super(key: key, child: child); static MixThemeData of(BuildContext context) { return context.dependOnInheritedWidgetOfExactType()?.data ?? @@ -25,107 +22,165 @@ class MixTheme extends InheritedWidget { return context.dependOnInheritedWidgetOfExactType()?.data; } + final MixThemeData data; + @override - bool updateShouldNotify(MixTheme oldWidget) { - return data != oldWidget.data; - } + bool updateShouldNotify(MixTheme oldWidget) => data != oldWidget.data; } -class MixThemeData with EqualityMixin { - final MixSpaceTokens space; - late MixSpaceTokensReference spaceRef; - final MixBreakpointsTokens breakpoints; +@immutable +class MixThemeData with Comparable { + final DesignTokenMap space; - final MixColorTokens colors; - final MixTextStyleTokens textStyles; + final DesignTokenMap breakpoints; + final DesignTokenMap colors; - MixThemeData.raw({ - required this.space, + final DesignTokenMap textStyles; + final DesignTokenMap radii; + + const MixThemeData.raw({ required this.breakpoints, required this.colors, + required this.space, required this.textStyles, - }) { - // Creates a refernece map of the tokens - spaceRef = space.map((key, value) => MapEntry(key.ref, key)); - } + required this.radii, + }); + + const MixThemeData.empty() + : this.raw( + breakpoints: const {}, + colors: const {}, + space: const {}, + textStyles: const {}, + radii: const {}, + ); factory MixThemeData({ - MixSpaceTokens? space, - MixBreakpointsTokens? breakpoints, - MixColorTokens? colors, - MixTextStyleTokens? textStyles, + DesignTokenMap? breakpoints, + DesignTokenMap? colors, + DesignTokenMap? space, + DesignTokenMap? textStyles, + DesignTokenMap? radii, }) { return MixThemeData.raw( - space: {...?space, ...SpaceTokens.tokens}, - breakpoints: breakpoints ?? const MixBreakpointsTokens(), - colors: {...?colors, ...$MDColorScheme.tokens}, - textStyles: {...?textStyles, ...$M3Text.tokens, ...$M2Text.tokens}, + breakpoints: {..._defaultBreakpoints, ...?breakpoints}, + colors: {...?colors}, + space: {..._defaultSpace, ...?space}, + textStyles: {...?textStyles}, + radii: {...?radii}, ); } MixThemeData copyWith({ - MixSpaceTokens? space, - MixBreakpointsTokens? breakpoints, - MixRadiiTokens? radii, - MixColorTokens? colors, - MixTextStyleTokens? textStyles, + DesignTokenMap? breakpoints, + DesignTokenMap? colors, + DesignTokenMap? space, + DesignTokenMap? textStyles, + DesignTokenMap? radii, }) { return MixThemeData.raw( - space: {...this.space, ...?space}, breakpoints: breakpoints ?? this.breakpoints, - colors: {...this.colors, ...?colors}, - textStyles: {...this.textStyles, ...?textStyles}, + colors: colors ?? this.colors, + space: space ?? this.space, + textStyles: textStyles ?? this.textStyles, + radii: radii ?? this.radii, ); } @override - get props => [space, breakpoints, colors, textStyles]; + get props => [space, breakpoints, colors, textStyles, radii]; } +final DesignTokenMap _defaultSpace = { + SpaceToken.xsmall: (context) => 4.0, + SpaceToken.small: (context) => 8.0, + SpaceToken.medium: (context) => 16.0, + SpaceToken.large: (context) => 24.0, + SpaceToken.xlarge: (context) => 36.0, + SpaceToken.xxlarge: (context) => 72.0, +}; + +final DesignTokenMap + _defaultBreakpoints = { + BreakpointToken.xsmall: (context) => + const BreakpointConstraint(maxWidth: 599), + BreakpointToken.small: (context) => + const BreakpointConstraint(minWidth: 600, maxWidth: 1023), + BreakpointToken.medium: (context) => + const BreakpointConstraint(minWidth: 1024, maxWidth: 1439), + BreakpointToken.large: (context) => + const BreakpointConstraint(minWidth: 1440, maxWidth: double.infinity), +}; + class MixTokenResolver { final BuildContext context; - MixTokenResolver(this.context); + const MixTokenResolver(this.context); - MixThemeData get theme => MixTheme.of(context); + MixThemeData get _theme => MixTheme.of(context); - Color color(ColorToken token) { - final color = theme.colors[token]?.call(context); + Color colorToken(ColorToken token) { + final color = _theme.colors[token]?.call(context); - if (color == null) { - throw Exception('Color token $token is not defined in Mix Theme'); + if (color != null) return color; + + if (token is ColorTokenResolver) { + return token.resolve(context); } - return color; + assert(color != null, 'Color token $token is not defined in Mix Theme'); + + return color ?? Colors.transparent; } - TextStyle textStyle(TextStyleToken token) { - final style = theme.textStyles[token]?.call(context); + Radius radiiToken(RadiusToken token) { + final radius = _theme.radii[token]?.call(context); + + if (radius != null) return radius; - if (style == null) { - throw Exception('TextStyle token $token is not defined in Mix Theme'); + if (token is RadiusTokenResolver) { + return token.resolve(context); } - return style; - } + assert( + radius != null, + 'Radii token $token is not defined in Mix Themem or it needs to have a token resolver', + ); - double space(double value) { - final mixTheme = theme; + return radius ?? Radius.zero; + } - // Check if value is a reference - final token = mixTheme.spaceRef[value]; + TextStyle textStyleToken(TextStyleToken token) { + final style = _theme.textStyles[token]?.call(context); + if (style != null) return style; - // if value is not a reference return value - if (token == null) { - return value; + if (token is TextStyleTokenResolver) { + return token.resolve(context); } - final space = mixTheme.space[token]?.call(context); + assert(style != null, 'TextStyle token $token is not defined in Mix Theme'); - if (space == null) { - throw Exception('Spacetoken $token is not defined in Mix Theme'); - } + return style ?? const TextStyle(); + } + + double spaceToken(SpaceToken token) { + final space = _theme.space[token]?.call(context); + + if (space != null) return space; + + assert(space != null, 'SpaceToken: $token is not defined in Mix Theme'); + + return space ?? 0; + } + + double spaceTokenRef(double value) { + if (value == 0 || value > 0) return value; + final token = _theme.space.keys.firstWhereOrNull( + (key) => key() == value, + ); + + assert(token != null, 'SpaceToken: $value is not defined in Mix Theme'); - return space; + return token == null ? value : spaceToken(token); } } diff --git a/lib/src/theme/tokens/breakpoints.dart b/lib/src/theme/tokens/breakpoints.dart index 00e7b7a4c..02123d5e8 100644 --- a/lib/src/theme/tokens/breakpoints.dart +++ b/lib/src/theme/tokens/breakpoints.dart @@ -1,72 +1,41 @@ import 'package:flutter/material.dart'; -enum ScreenSizeToken { xsmall, small, medium, large } +import 'mix_token.dart'; -class MixBreakpointsTokens { - final double xsmall; - final double small; - final double medium; - final double large; +enum BreakpointOrientation { + portrait, + landscape, + all, +} - const MixBreakpointsTokens.raw({ - required this.xsmall, - required this.small, - required this.medium, - required this.large, - }); +class BreakpointConstraint { + final double minWidth; + final double maxWidth; + final BreakpointOrientation orientation; - const MixBreakpointsTokens({ - this.xsmall = 0, - this.small = 600, - this.medium = 1240, - this.large = 1440, + const BreakpointConstraint({ + this.minWidth = 0, + this.maxWidth = double.infinity, + this.orientation = BreakpointOrientation.all, }); - /// Returns [ScreenSizeToken] based on Material breakpoints - ScreenSizeToken getScreenSize(BuildContext context) { - final screenWidth = MediaQuery.of(context).size.width; - - return screenWidth >= large - ? ScreenSizeToken.large - : screenWidth >= medium - ? ScreenSizeToken.medium - : screenWidth >= small - ? ScreenSizeToken.small - : ScreenSizeToken.xsmall; - } - - MixBreakpointsTokens copyWith({ - double? xsmall, - double? small, - double? medium, - double? large, - }) { - return MixBreakpointsTokens.raw( - xsmall: xsmall ?? this.xsmall, - small: small ?? this.small, - medium: medium ?? this.medium, - large: large ?? this.large, - ); - } - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; + bool matches(Size size) { + final matchesWidth = size.width >= minWidth && size.width <= maxWidth; + final matchesOrientation = orientation == BreakpointOrientation.all || + (orientation == BreakpointOrientation.portrait && + size.height > size.width) || + (orientation == BreakpointOrientation.landscape && + size.width > size.height); - return other is MixBreakpointsTokens && - other.xsmall == xsmall && - other.small == small && - other.medium == medium && - other.large == large; + return matchesWidth && matchesOrientation; } +} - @override - int get hashCode { - return xsmall.hashCode ^ small.hashCode ^ medium.hashCode ^ large.hashCode; - } +class BreakpointToken extends MixToken { + static const xsmall = BreakpointToken('--mix-breakpoint-xsmall'); + static const small = BreakpointToken('--mix-breakpoint-small'); + static const medium = BreakpointToken('--mix-breakpoint-medium'); + static const large = BreakpointToken('--mix-breakpoint-large'); - @override - String toString() { - return 'MixThemeBreakpoints(xsmall: $xsmall, small: $small, medium: $medium, large: $large)'; - } + const BreakpointToken(super.name); } diff --git a/lib/src/theme/tokens/color_token.dart b/lib/src/theme/tokens/color_token.dart index 3633de280..946d88b68 100644 --- a/lib/src/theme/tokens/color_token.dart +++ b/lib/src/theme/tokens/color_token.dart @@ -3,38 +3,26 @@ import 'package:flutter/widgets.dart'; import 'mix_token.dart'; -class ColorSwatchToken extends ColorSwatch implements MixToken { - const ColorSwatchToken(this.name) : super(0, const {}); - +class ColorToken extends Color implements MixToken { @override final String name; - @override - bool operator ==(Object other) => - identical(this, other) || - other is ColorSwatchToken && - runtimeType == other.runtimeType && - name == other.name; + const ColorToken(this.name) : super(0); @override - int get hashCode => runtimeType.hashCode ^ name.hashCode; -} + operator ==(Object other) { + if (identical(this, other)) return true; -class ColorToken extends Color implements MixToken { - const ColorToken(this.name) : super(0); + return other is ColorToken && other.name == name; + } @override - final String name; + int get hashCode => name.hashCode; +} +class ColorTokenResolver extends ColorToken with TokenResolver { @override - bool operator ==(Object other) => - identical(this, other) || - other is ColorToken && - runtimeType == other.runtimeType && - name == other.name; + final Color Function(BuildContext context) tokenResolver; - @override - int get hashCode => runtimeType.hashCode ^ name.hashCode; + const ColorTokenResolver(super.name, this.tokenResolver); } - -typedef MixColorTokens = TokenReferenceMap; diff --git a/lib/src/theme/tokens/material_tokens.dart b/lib/src/theme/tokens/material_tokens.dart new file mode 100644 index 000000000..d18844c33 --- /dev/null +++ b/lib/src/theme/tokens/material_tokens.dart @@ -0,0 +1,199 @@ +// ignore_for_file: deprecated_member_use, avoid-non-null-assertion + +import 'package:flutter/material.dart'; + +import 'color_token.dart'; +import 'text_style_token.dart'; + +@immutable +class _MaterialDesignColors { + final primary = ColorTokenResolver( + '--md-color-primary', + (context) => Theme.of(context).colorScheme.primary, + ); + + final secondary = ColorTokenResolver( + '--md-color-secondary', + (context) => Theme.of(context).colorScheme.secondary, + ); + + final tertiary = ColorTokenResolver( + '--md-color-tertiary', + (context) => Theme.of(context).colorScheme.tertiary, + ); + + final surface = ColorTokenResolver( + '--md-color-surface', + (context) => Theme.of(context).colorScheme.surface, + ); + + final background = ColorTokenResolver( + '--md-color-background', + (context) => Theme.of(context).colorScheme.background, + ); + + final error = ColorTokenResolver( + '--md-color-error', + (context) => Theme.of(context).colorScheme.error, + ); + + final onPrimary = ColorTokenResolver( + '--md-color-on-primary', + (context) => Theme.of(context).colorScheme.onPrimary, + ); + + final onSecondary = ColorTokenResolver( + '--md-color-on-secondary', + (context) => Theme.of(context).colorScheme.onSecondary, + ); + + final onTertiary = ColorTokenResolver( + '--md-color-on-tertiary', + (context) => Theme.of(context).colorScheme.onTertiary, + ); + + final onSurface = ColorTokenResolver( + '--md-color-on-surface', + (context) => Theme.of(context).colorScheme.onSurface, + ); + + final onBackground = ColorTokenResolver( + '--md-color-on-background', + (context) => Theme.of(context).colorScheme.onBackground, + ); + + final onError = ColorTokenResolver( + '--md-color-on-error', + (context) => Theme.of(context).colorScheme.onError, + ); + + _MaterialDesignColors(); +} + +@immutable +// Material 3 TextTheme Tokens. +class _MaterialTextStyles { + // Material 3 text styles + final displayLarge = TextStyleTokenResolver( + '--md3-display-large', + (context) => Theme.of(context).textTheme.displayLarge!, + ); + final displayMedium = TextStyleTokenResolver( + '--md3-display-medium', + (context) => Theme.of(context).textTheme.displayMedium!, + ); + final displaySmall = TextStyleTokenResolver( + '--md3-display-small', + (context) => Theme.of(context).textTheme.displaySmall!, + ); + final headlineLarge = TextStyleTokenResolver( + '--md3-headline-large', + (context) => Theme.of(context).textTheme.headlineLarge!, + ); + final headlineMedium = TextStyleTokenResolver( + '--md3-headline-medium', + (context) => Theme.of(context).textTheme.headlineMedium!, + ); + final headlineSmall = TextStyleTokenResolver( + '--md3-headline-small', + (context) => Theme.of(context).textTheme.headlineSmall!, + ); + final titleLarge = TextStyleTokenResolver( + '--md3-title-large', + (context) => Theme.of(context).textTheme.titleLarge!, + ); + final titleMedium = TextStyleTokenResolver( + '--md3-title-medium', + (context) => Theme.of(context).textTheme.titleMedium!, + ); + final titleSmall = TextStyleTokenResolver( + '--md3-title-small', + (context) => Theme.of(context).textTheme.titleSmall!, + ); + final bodyLarge = TextStyleTokenResolver( + '--md3-body-large', + (context) => Theme.of(context).textTheme.bodyLarge!, + ); + final bodyMedium = TextStyleTokenResolver( + '--md3-body-medium', + (context) => Theme.of(context).textTheme.bodyMedium!, + ); + final bodySmall = TextStyleTokenResolver( + '--md3-body-small', + (context) => Theme.of(context).textTheme.bodySmall!, + ); + final labelLarge = TextStyleTokenResolver( + '--md3-label-large', + (context) => Theme.of(context).textTheme.labelLarge!, + ); + final labelMedium = TextStyleTokenResolver( + '--md3-label-medium', + (context) => Theme.of(context).textTheme.labelMedium!, + ); + final labelSmall = TextStyleTokenResolver( + '--md3-label-small', + (context) => Theme.of(context).textTheme.labelSmall!, + ); + // Material 2 text styles + final headline1 = TextStyleTokenResolver( + '--md2-text-style-headline1', + (context) => Theme.of(context).textTheme.headline1!, + ); + final headline2 = TextStyleTokenResolver( + '--md2-text-style-headline2', + (context) => Theme.of(context).textTheme.headline2!, + ); + final headline3 = TextStyleTokenResolver( + '--md2-text-style-headline3', + (context) => Theme.of(context).textTheme.headline3!, + ); + final headline4 = TextStyleTokenResolver( + '--md2-text-style-headline4', + (context) => Theme.of(context).textTheme.headline4!, + ); + final headline5 = TextStyleTokenResolver( + '--md2-text-style-headline5', + (context) => Theme.of(context).textTheme.headline5!, + ); + final headline6 = TextStyleTokenResolver( + '--md2-text-style-headline6', + (context) => Theme.of(context).textTheme.headline6!, + ); + final subtitle1 = TextStyleTokenResolver( + '--md2-text-style-subtitle1', + (context) => Theme.of(context).textTheme.subtitle1!, + ); + final subtitle2 = TextStyleTokenResolver( + '--md2-text-style-subtitle2', + (context) => Theme.of(context).textTheme.subtitle2!, + ); + final bodyText1 = TextStyleTokenResolver( + '--md2-text-style-bodyText1', + (context) => Theme.of(context).textTheme.bodyText1!, + ); + final bodyText2 = TextStyleTokenResolver( + '--md2-text-style-bodyText2', + (context) => Theme.of(context).textTheme.bodyText2!, + ); + final caption = TextStyleTokenResolver( + '--md2-text-style-caption', + (context) => Theme.of(context).textTheme.caption!, + ); + final button = TextStyleTokenResolver( + '--md2-text-style-button', + (context) => Theme.of(context).textTheme.button!, + ); + final overline = TextStyleTokenResolver( + '--md2-text-style-overline', + (context) => Theme.of(context).textTheme.overline!, + ); + + _MaterialTextStyles(); +} + +@immutable +class MaterialTokens { + final colors = _MaterialDesignColors(); + final textStyles = _MaterialTextStyles(); + MaterialTokens(); +} diff --git a/lib/src/theme/tokens/mix_token.dart b/lib/src/theme/tokens/mix_token.dart index 7fc860b42..835c642c3 100644 --- a/lib/src/theme/tokens/mix_token.dart +++ b/lib/src/theme/tokens/mix_token.dart @@ -1,36 +1,33 @@ import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; -import '../../../mix.dart'; - -abstract class MixToken { +@immutable +abstract class MixToken { final String name; - const MixToken(this.name); - @override - bool operator ==(Object other) => - identical(this, other) || - other is MixToken && - runtimeType == other.runtimeType && - name == other.name; + const MixToken(this.name); @override - int get hashCode => runtimeType.hashCode ^ name.hashCode; -} + operator ==(Object other) { + if (identical(this, other)) return true; -mixin WithReferenceMixin on MixToken { - // Refernce is negativce for tracking - // Also reference are passed as double to DTOs + if (runtimeType != other.runtimeType) return false; - double get ref => hashCode.toDouble() * -1; - double call() { - // Creates a reference from hashcode - return ref; + return other is MixToken && other.name == name; } + + @override + int get hashCode => Object.hash(name, runtimeType); } -typedef TokenReferenceMap = Map>; +mixin TokenResolver on MixToken { + T Function(BuildContext context) get tokenResolver; + T resolve(BuildContext context) => tokenResolver(context); +} -typedef MixTextStyleTokens = TokenReferenceMap; +mixin TokenValueReference on MixToken { + T call(); +} -typedef TokenValueGetter = T Function(BuildContext); +typedef DesignTokenMap + = Map; diff --git a/lib/src/theme/tokens/radii_token.dart b/lib/src/theme/tokens/radii_token.dart deleted file mode 100644 index 895c6e239..000000000 --- a/lib/src/theme/tokens/radii_token.dart +++ /dev/null @@ -1,9 +0,0 @@ -import 'package:flutter/material.dart'; - -import 'mix_token.dart'; - -class RadiiToken extends MixToken with WithReferenceMixin { - const RadiiToken(super.name); -} - -typedef MixRadiiTokens = TokenReferenceMap; diff --git a/lib/src/theme/tokens/radius_token.dart b/lib/src/theme/tokens/radius_token.dart new file mode 100644 index 000000000..8f1b6ef0a --- /dev/null +++ b/lib/src/theme/tokens/radius_token.dart @@ -0,0 +1,67 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import 'mix_token.dart'; + +@immutable +class RadiiTokenUtil { + final small = RadiusToken.small; + final medium = RadiusToken.medium; + final large = RadiusToken.large; + + const RadiiTokenUtil(); +} + +@immutable +class RadiusToken extends Radius implements MixToken { + static const small = RadiusToken('--mix-radii-small'); + static const medium = RadiusToken('--mix-radii-medium'); + static const large = RadiusToken('--mix-radii-large'); + + @override + final String name; + + const RadiusToken(this.name) : super.circular(0); + + @override + operator ==(Object other) { + if (identical(this, other)) return true; + + return other is RadiusToken && other.name == name; + } + + @override + int get hashCode => name.hashCode; +} + +@immutable +class RadiusTokenResolver extends RadiusToken with TokenResolver { + @override + final Radius Function(BuildContext context) tokenResolver; + + const RadiusTokenResolver(super.name, this.tokenResolver); +} + +// // Helper class to wrap functions that can return +// a Radius token that resmebles the WithSpaceToken +@immutable +class UtilityWithRadiusTokens { + final T Function(Radius value) _fn; + + const UtilityWithRadiusTokens(T Function(Radius value) fn) : _fn = fn; + + factory UtilityWithRadiusTokens.shorthand( + T Function(Radius p1, [Radius? p2, Radius? p3, Radius? p4]) fn, + ) { + // Need to accept a type with positional params, and convert it into a function that accepts a double and returns T + return UtilityWithRadiusTokens((Radius value) => fn(value)); + } + + T get small => call(RadiusToken.small); + + T get medium => call(RadiusToken.medium); + + T get large => call(RadiusToken.large); + + T call(Radius value) => _fn(value); +} diff --git a/lib/src/theme/tokens/space_token.dart b/lib/src/theme/tokens/space_token.dart index 3d108416c..4fc9ca2eb 100644 --- a/lib/src/theme/tokens/space_token.dart +++ b/lib/src/theme/tokens/space_token.dart @@ -1,10 +1,27 @@ +import 'package:flutter/material.dart'; + import 'mix_token.dart'; -// Define default -class SpaceTokens { - SpaceTokens._(); +@immutable +class SpaceTokenUtil { + final xsmall = SpaceToken.xsmall(); + final small = SpaceToken.small(); + final medium = SpaceToken.medium(); + final large = SpaceToken.large(); + final xlarge = SpaceToken.xlarge(); + final xxlarge = SpaceToken.xxlarge(); + SpaceTokenUtil(); +} + +typedef SpaceTokenRef = double; - // Define your tokens +/// A class representing a space token, which extends `MixToken` class +/// and uses the `SizeTokenMixin` mixin. +/// +/// A space token defines a value for controlling the +/// size of UI elements. +@immutable +class SpaceToken extends MixToken with TokenValueReference { static const xsmall = SpaceToken('--mix-space-xsmall'); static const small = SpaceToken('--mix-space-small'); static const medium = SpaceToken('--mix-space-medium'); @@ -12,64 +29,35 @@ class SpaceTokens { static const xlarge = SpaceToken('--mix-space-xlarge'); static const xxlarge = SpaceToken('--mix-space-xxlarge'); - static MixSpaceTokens get tokens => { - SpaceTokens.xsmall: (context) => 4.0, - SpaceTokens.small: (context) => 8.0, - SpaceTokens.medium: (context) => 16.0, - SpaceTokens.large: (context) => 24.0, - SpaceTokens.xlarge: (context) => 36.0, - SpaceTokens.xxlarge: (context) => 72.0, - }; -} - -/// A class representing a space token, which extends `MixToken` class -/// and uses the `SizeTokenMixin` mixin. -/// -/// A space token defines a value for controlling the -/// size of UI elements. -class SpaceToken extends MixToken with WithReferenceMixin { /// A constant constructor that accepts a `String` argument named [name]. /// Name needs to be unique per token /// /// [name] is used to initialize the superclass `MixToken`. const SpaceToken(super.name); -} -typedef MixSpaceTokens = TokenReferenceMap; - -typedef MixSpaceTokensReference = Map; + @override + double call() => hashCode * -1.0; +} // Helper class to wrap functions that can return // Space tokens in their methods -class WrapWithSpaceTokens { - const WrapWithSpaceTokens(T Function(double value) fn) : _fn = fn; - +@immutable +class UtilityWithSpaceTokens { final T Function(double value) _fn; - T call(double value) => _fn(value); + const UtilityWithSpaceTokens(T Function(double value) fn) : _fn = fn; - T get xsmall => call(SpaceTokens.xsmall.ref); + T get xsmall => call(SpaceToken.xsmall()); - T get small => call(SpaceTokens.small.ref); + T get small => call(SpaceToken.small()); - T get medium => call(SpaceTokens.medium.ref); + T get medium => call(SpaceToken.medium()); - T get large => call(SpaceTokens.large.ref); + T get large => call(SpaceToken.large()); - T get xlarge => call(SpaceTokens.xlarge.ref); + T get xlarge => call(SpaceToken.xlarge()); - T get xxlarge => call(SpaceTokens.xxlarge.ref); + T get xxlarge => call(SpaceToken.xxlarge()); - @Deprecated('Use medium instead') - T get md => medium; - @Deprecated('Use small instead') - T get sm => small; - @Deprecated('Use large instead') - T get lg => large; - @Deprecated('Use xlarge instead') - T get xl => xlarge; - @Deprecated('Use xsmall instead') - T get xs => xsmall; - @Deprecated('Use xxlarge instead') - T get xxl => xxlarge; + T call(double value) => _fn(value); } diff --git a/lib/src/theme/tokens/text_style_token.dart b/lib/src/theme/tokens/text_style_token.dart index af505e380..37612cbc3 100644 --- a/lib/src/theme/tokens/text_style_token.dart +++ b/lib/src/theme/tokens/text_style_token.dart @@ -1,20 +1,29 @@ +import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'mix_token.dart'; -class TextStyleToken extends TextStyle implements MixToken { +class TextStyleToken extends TextStyle implements MixToken { + @override + final String name; + const TextStyleToken(this.name); @override - final String name; + operator ==(Object other) { + if (identical(this, other)) return true; + + return other is TextStyleToken && other.name == name; + } @override - bool operator ==(Object other) => - identical(this, other) || - other is TextStyleToken && - runtimeType == other.runtimeType && - name == other.name; + int get hashCode => name.hashCode; +} +class TextStyleTokenResolver extends TextStyleToken + with TokenResolver { @override - int get hashCode => runtimeType.hashCode ^ name.hashCode; + final TextStyle Function(BuildContext context) tokenResolver; + + const TextStyleTokenResolver(super.name, this.tokenResolver); } diff --git a/lib/src/theme/tokens/token_util.dart b/lib/src/theme/tokens/token_util.dart new file mode 100644 index 000000000..b1d0cef92 --- /dev/null +++ b/lib/src/theme/tokens/token_util.dart @@ -0,0 +1,7 @@ +import 'material_tokens.dart'; +import 'radius_token.dart'; +import 'space_token.dart'; + +final $md = MaterialTokens(); +const $radii = RadiiTokenUtil(); +final $space = SpaceTokenUtil(); diff --git a/lib/src/utils/alignment_util.dart b/lib/src/utils/alignment_util.dart new file mode 100644 index 000000000..552a6ba79 --- /dev/null +++ b/lib/src/utils/alignment_util.dart @@ -0,0 +1,72 @@ +import 'package:flutter/material.dart'; + +// Import custom attributes and extension methods +import '../attributes/alignment_attribute.dart'; +import '../helpers/extensions/values_ext.dart'; + +/// Converts an [x] and [y] value into an [AlignmentAttribute] object. +/// +/// The [x] and [y] values are used to create an [Alignment] object. +/// The [Alignment] object is then converted into an [AlignmentAttribute] object. +const alignment = AlignmentAttribute.pos; + +/// Convers a [start] and [y] value into an [AlignmentDirectionalAttribute] object. +const alignmentDirectional = AlignmentDirectionalAttribute.pos; + +// Convenience methods follow below, providing predefined [AlignmentGeometryAttribute]s for common alignments. +// These methods simplify the creation of [AlignmentGeometryAttribute] objects by abstracting away +// the need to directly use the [Alignment] class. + +/// Provides an [AlignmentAttribute] for top-left alignment. +AlignmentAttribute alignmentTopLeft() => Alignment.topLeft.toAttribute(); + +/// Provides an [AlignmentAttribute] for top-center alignment. +AlignmentAttribute alignmentTopCenter() => Alignment.topCenter.toAttribute(); + +/// Provides an [AlignmentAttribute] for top-right alignment. +AlignmentAttribute alignmentTopRight() => Alignment.topRight.toAttribute(); + +/// Provides an [AlignmentAttribute] for center-left alignment. +AlignmentAttribute alignmentCenterLeft() => Alignment.centerLeft.toAttribute(); + +/// Provides an [AlignmentAttribute] for center alignment. +AlignmentAttribute alignmentCenter() => Alignment.center.toAttribute(); + +/// Provides an [AlignmentAttribute] for center-right alignment. +AlignmentAttribute alignmentCenterRight() => + Alignment.centerRight.toAttribute(); + +/// Provides an [AlignmentGeometryAttribute] for bottom-left alignment. +AlignmentAttribute alignmentBottomLeft() => Alignment.bottomLeft.toAttribute(); + +/// Provides an [AlignmentAttribute] for bottom-center alignment. +AlignmentAttribute alignmentBottomCenter() => + Alignment.bottomCenter.toAttribute(); + +/// Provides an [AlignmentAttribute] for bottom-right alignment. +AlignmentAttribute alignmentBottomRight() => + Alignment.bottomRight.toAttribute(); + +/// Provides an [AlignmentGeometryAttribute] for top-start alignment considering text direction. +AlignmentDirectionalAttribute alignmentTopStart() => + AlignmentDirectional.topStart.toAttribute(); + +/// Provides an [AlignmentDirectionalAttribute] for top-end alignment considering text direction. +AlignmentDirectionalAttribute alignmentTopEnd() => + AlignmentDirectional.topEnd.toAttribute(); + +/// Provides an [AlignmentDirectionalAttribute] for center-start alignment considering text direction. +AlignmentDirectionalAttribute alignmentCenterStart() => + AlignmentDirectional.centerStart.toAttribute(); + +/// Provides an [AlignmentDirectionalAttribute] for center-end alignment considering text direction. +AlignmentDirectionalAttribute alignmentCenterEnd() => + AlignmentDirectional.centerEnd.toAttribute(); + +/// Provides an [AlignmentDirectionalAttribute] for bottom-start alignment considering text direction. +AlignmentDirectionalAttribute alignmentBottomStart() => + AlignmentDirectional.bottomStart.toAttribute(); + +/// Provides an [AlignmentDirectionalAttribute] for bottom-end alignment considering text direction. +AlignmentDirectionalAttribute alignmentBottomEnd() => + AlignmentDirectional.bottomEnd.toAttribute(); diff --git a/lib/src/utils/border_radius_util.dart b/lib/src/utils/border_radius_util.dart new file mode 100644 index 000000000..3bec774b6 --- /dev/null +++ b/lib/src/utils/border_radius_util.dart @@ -0,0 +1,101 @@ +import 'package:flutter/material.dart'; + +import '../attributes/border/border_radius_attribute.dart'; + +// Provides an utility for creating a uniform BorderRadiusAttribute for all corners. +const borderRadius = BorderRadiusAttribute.positional; + +// Border Radius Directional +// Provides a utility BorderRadiusDirectionalAttribute for all corners, considering text direction. +const borderRadiusDirectional = BorderRadiusDirectionalAttribute.positional; + +// Provides an utility for creating a vertical BorderRadiusAttribute with independent radii for top and bottom sides. +const borderRadiusVertical = BorderRadiusAttribute.vertical; + +// Provides an utility for creating a horizontal BorderRadiusAttribute with independent radii for left and right sides. +const borderRadiusHorizontal = BorderRadiusAttribute.horizontal; + +// Provides an utility for creating a BorderRadiusAttribute with zero radius, resulting in square corners. +const borderRadiusOnly = BorderRadiusAttribute.new; + +const borderRadiusDirectionalOnly = BorderRadiusDirectionalAttribute.new; + +// Alias for creating a uniform circular BorderRadiusDirectionalAttribute. +BorderRadiusAttribute rounded(double p1, [double? p2, double? p3, double? p4]) { + final r1 = Radius.circular(p1); + Radius? r2 = p2 == null ? null : Radius.circular(p2); + Radius? r3 = p3 == null ? null : Radius.circular(p3); + Radius? r4 = p4 == null ? null : Radius.circular(p4); + + return BorderRadiusAttribute.positional(r1, r2, r3, r4); +} + +BorderRadiusDirectionalAttribute roundedDirectional( + double p1, [ + double? p2, + double? p3, + double? p4, +]) { + final r1 = Radius.circular(p1); + Radius? r2 = p2 == null ? null : Radius.circular(p2); + Radius? r3 = p3 == null ? null : Radius.circular(p3); + Radius? r4 = p4 == null ? null : Radius.circular(p4); + + return BorderRadiusDirectionalAttribute.positional(r1, r2, r3, r4); +} + +// Corner-specific BorderRadiusAttributes +// Creates a BorderRadiusAttribute with a circular radius applied to the top-left corner. +BorderRadiusAttribute roundedTopLeft(double radius) { + return BorderRadiusAttribute(topLeft: Radius.circular(radius)); +} + +// Creates a BorderRadiusAttribute with a circular radius applied to the top-right corner. +BorderRadiusAttribute roundedTopRight(double radius) { + return BorderRadiusAttribute(topRight: Radius.circular(radius)); +} + +// Creates a BorderRadiusAttribute with a circular radius applied to the bottom-left corner. +BorderRadiusAttribute roundedBottomLeft(double radius) { + return BorderRadiusAttribute(bottomLeft: Radius.circular(radius)); +} + +// Creates a BorderRadiusAttribute with a circular radius applied to the bottom-right corner. +BorderRadiusAttribute roundedBottomRight(double radius) { + return BorderRadiusAttribute(bottomRight: Radius.circular(radius)); +} + +// Corner-specific BorderRadiusDirectionalAttributes +// Creates a BorderRadiusDirectionalAttribute with a circular radius applied to the top-start corner, considering text direction. +BorderRadiusDirectionalAttribute roundedTopStart(double radius) { + return BorderRadiusDirectionalAttribute(topStart: Radius.circular(radius)); +} + +// Creates a BorderRadiusDirectionalAttribute with a circular radius applied to the top-end corner, considering text direction. +BorderRadiusDirectionalAttribute roundedTopEnd(double radius) { + return BorderRadiusDirectionalAttribute(topEnd: Radius.circular(radius)); +} + +BorderRadiusAttribute roundedHorizontal({double? left, double? right}) { + return BorderRadiusAttribute.horizontal( + left: left == null ? null : Radius.circular(left), + right: right == null ? null : Radius.circular(right), + ); +} + +BorderRadiusAttribute roundedVertical({double? top, double? bottom}) { + return BorderRadiusAttribute.vertical( + top: top == null ? null : Radius.circular(top), + bottom: bottom == null ? null : Radius.circular(bottom), + ); +} + +// Creates a BorderRadiusDirectionalAttribute with a circular radius applied to the bottom-start corner, considering text direction. +BorderRadiusDirectionalAttribute roundedBottomStart(double radius) { + return BorderRadiusDirectionalAttribute(bottomStart: Radius.circular(radius)); +} + +// Creates a BorderRadiusDirectionalAttribute with a circular radius applied to the bottom-end corner, considering text direction. +BorderRadiusDirectionalAttribute roundedBottomEnd(double radius) { + return BorderRadiusDirectionalAttribute(bottomEnd: Radius.circular(radius)); +} diff --git a/lib/src/utils/border_util.dart b/lib/src/utils/border_util.dart new file mode 100644 index 000000000..fbc5687d7 --- /dev/null +++ b/lib/src/utils/border_util.dart @@ -0,0 +1,199 @@ +import 'package:flutter/material.dart'; + +import '../attributes/border/border_attribute.dart'; +import '../helpers/extensions/values_ext.dart'; + +BorderAttribute border({ + Color? color, + double? width, + BorderStyle? style, + double? strokeAlign, +}) { + final side = borderSide( + color: color, + width: width, + style: style, + strokeAlign: strokeAlign, + ); + + return BorderAttribute(left: side, right: side, top: side, bottom: side); +} + +const borderOnly = BorderAttribute.new; + +BorderDirectionalAttribute borderDirectional({ + Color? color, + double? width, + BorderStyle? style, + double? strokeAlign, +}) { + final side = borderSide( + color: color, + width: width, + style: style, + strokeAlign: strokeAlign, + ); + + return BorderDirectionalAttribute( + start: side, + end: side, + top: side, + bottom: side, + ); +} + +const borderDirectionalOnly = BorderDirectionalAttribute.new; + +BorderAttribute borderTop({ + Color? color, + double? width, + BorderStyle? style, + double? strokeAlign, +}) { + return BorderAttribute( + top: borderSide( + color: color, + width: width, + style: style, + strokeAlign: strokeAlign, + ), + ); +} + +BorderAttribute borderBottom({ + Color? color, + double? width, + BorderStyle? style, + double? strokeAlign, +}) { + return BorderAttribute( + bottom: borderSide( + color: color, + width: width, + style: style, + strokeAlign: strokeAlign, + ), + ); +} + +BorderAttribute borderLeft({ + Color? color, + double? width, + BorderStyle? style, + double? strokeAlign, +}) { + return BorderAttribute( + left: borderSide( + color: color, + width: width, + style: style, + strokeAlign: strokeAlign, + ), + ); +} + +BorderAttribute borderRight({ + Color? color, + double? width, + BorderStyle? style, + double? strokeAlign, +}) { + return BorderAttribute( + right: borderSide( + color: color, + width: width, + style: style, + strokeAlign: strokeAlign, + ), + ); +} + +BorderDirectionalAttribute borderStart({ + Color? color, + double? width, + BorderStyle? style, + double? strokeAlign, +}) { + return BorderDirectionalAttribute( + start: borderSide( + color: color, + width: width, + style: style, + strokeAlign: strokeAlign, + ), + ); +} + +BorderDirectionalAttribute borderEnd({ + Color? color, + double? width, + BorderStyle? style, + double? strokeAlign, +}) { + return BorderDirectionalAttribute( + end: borderSide( + color: color, + width: width, + style: style, + strokeAlign: strokeAlign, + ), + ); +} + +BorderAttribute borderHorizontal({ + Color? color, + double? width, + BorderStyle? style, + double? strokeAlign, +}) { + return _borderSymetric( + horizontal: borderSide( + color: color, + width: width, + style: style, + strokeAlign: strokeAlign, + ), + ); +} + +BorderAttribute borderVertical({ + Color? color, + double? width, + BorderStyle? style, + double? strokeAlign, +}) { + return _borderSymetric( + vertical: borderSide( + color: color, + width: width, + style: style, + strokeAlign: strokeAlign, + ), + ); +} + +BorderAttribute _borderSymetric({ + BorderSideAttribute? vertical, + BorderSideAttribute? horizontal, +}) { + return BorderAttribute( + left: vertical, + right: vertical, + top: horizontal, + bottom: horizontal, + ); +} + +BorderSideAttribute borderSide({ + Color? color, + double? width, + BorderStyle? style, + double? strokeAlign, +}) { + return BorderSideAttribute( + color: color?.toAttribute(), + strokeAlign: strokeAlign, + style: style, + width: width, + ); +} diff --git a/lib/src/utils/box_constraints_util.dart b/lib/src/utils/box_constraints_util.dart new file mode 100644 index 000000000..61307a448 --- /dev/null +++ b/lib/src/utils/box_constraints_util.dart @@ -0,0 +1,21 @@ +import '../attributes/constraints_attribute.dart'; + +const boxConstraints = BoxConstraintsAttribute.new; + +BoxConstraintsAttribute width(double width) => + BoxConstraintsAttribute(width: width); + +BoxConstraintsAttribute height(double height) => + BoxConstraintsAttribute(height: height); + +BoxConstraintsAttribute minWidth(double width) => + BoxConstraintsAttribute(minWidth: width); + +BoxConstraintsAttribute maxWidth(double width) => + BoxConstraintsAttribute(maxWidth: width); + +BoxConstraintsAttribute minHeight(double height) => + BoxConstraintsAttribute(minHeight: height); + +BoxConstraintsAttribute maxHeight(double height) => + BoxConstraintsAttribute(maxHeight: height); diff --git a/lib/src/utils/context_variant_util.dart b/lib/src/utils/context_variant_util.dart new file mode 100644 index 000000000..93ab45347 --- /dev/null +++ b/lib/src/utils/context_variant_util.dart @@ -0,0 +1,104 @@ +import 'package:flutter/material.dart'; + +import '../helpers/extensions/string_ext.dart'; +import '../theme/mix_theme.dart'; +import '../theme/tokens/breakpoints.dart'; +import '../variants/context_variant.dart'; + +// Breakpoint context variants +final onSmall = _screenSizeVariant(BreakpointToken.small); + +final onXSmall = _screenSizeVariant(BreakpointToken.xsmall); + +final onMedium = _screenSizeVariant(BreakpointToken.medium); + +final onLarge = _screenSizeVariant(BreakpointToken.large); + +ContextVariant onBreakpoint({ + minWidth = 0, + maxWidth = double.infinity, + orientation = BreakpointOrientation.all, +}) { + final constraints = BreakpointConstraint( + minWidth: minWidth, + maxWidth: maxWidth, + orientation: orientation, + ); + final constraintName = + 'minWidth-${constraints.minWidth}-maxWidth-${constraints.maxWidth}-orientation-${constraints.orientation}'; + + return ContextVariant( + 'on-$constraintName', + when: (BuildContext context) { + final size = MediaQuery.sizeOf(context); + + return constraints.matches(size); + }, + ); +} + +// Brighness context variants +final onDark = _brightnessVariant(Brightness.dark); + +final onLight = _brightnessVariant(Brightness.light); + +// Directionality context variants +final onRTL = _directionalityVariant(TextDirection.rtl); +final onLTR = _directionalityVariant(TextDirection.ltr); + +// Orientation context variants + +final onPortrait = _orientationVariant(Orientation.portrait); + +final onLandscape = _orientationVariant(Orientation.landscape); + +ContextVariant _directionalityVariant(TextDirection direction) { + return ContextVariant( + 'on-${direction.name.paramCase}', + when: (BuildContext context) => Directionality.of(context) == direction, + ); +} + +ContextVariant _brightnessVariant(Brightness brightness) { + return ContextVariant( + 'on-${brightness.name.paramCase}', + when: (BuildContext context) { + return Theme.of(context).brightness == brightness; + }, + ); +} + +ContextVariant _screenSizeVariant(BreakpointToken screenSize) { + return ContextVariant( + 'on-${screenSize.name.paramCase}', + when: (BuildContext context) { + final breakpoints = MixTheme.of(context).breakpoints; + + final size = MediaQuery.sizeOf(context); + + final selectedbreakpoint = breakpoints[screenSize]; + + assert( + selectedbreakpoint != null, + 'Breakpoint ${screenSize.name} is not defined in the theme', + ); + + return selectedbreakpoint?.call(context).matches(size) ?? false; + }, + ); +} + +ContextVariant onNot(ContextVariant variant) { + return ContextVariant( + 'not(${variant.name})', + when: (BuildContext context) => !variant.when(context), + ); +} + +ContextVariant _orientationVariant(Orientation orientation) { + return ContextVariant( + 'on-${orientation.name.paramCase}', + when: (BuildContext context) => + MediaQuery.orientationOf(context) == orientation, + ); +} diff --git a/lib/src/utils/decoration_util.dart b/lib/src/utils/decoration_util.dart new file mode 100644 index 000000000..409ede40b --- /dev/null +++ b/lib/src/utils/decoration_util.dart @@ -0,0 +1,10 @@ +import 'package:flutter/material.dart'; + +import '../attributes/decoration_attribute.dart'; +import '../helpers/extensions/values_ext.dart'; + +BoxDecorationAttribute backgroundColor(Color color) { + return BoxDecorationAttribute(color: color.toAttribute()); +} + +const boxDecoration = BoxDecorationAttribute.new; diff --git a/lib/src/utils/decorators_util.dart b/lib/src/utils/decorators_util.dart new file mode 100644 index 000000000..a07ec07c5 --- /dev/null +++ b/lib/src/utils/decorators_util.dart @@ -0,0 +1,44 @@ +import 'package:flutter/material.dart'; + +import '../decorators/clip_decorator.dart'; +import '../decorators/default_decorators.dart'; + +const aspectRatio = AspectRatioDecorator.new; + +const expanded = FlexibleDecorator.tight; +const flexible = FlexibleDecorator.loose; + +const opacity = OpacityDecorator.new; + +const rotate = RotateDecorator.new; + +RotateDecorator rotate90() => rotate(1); +RotateDecorator rotate180() => rotate(2); +RotateDecorator rotate270() => rotate(3); + +const scale = ScaleDecorator.new; + +const clipRounded = clipRRect; +const clipOval = ClipOvalDecorator.new; +const clipPath = ClipPathDecorator.new; + +ClipRRectDecorator clipRRect( + double radius, { + CustomClipper? clipper, + Clip? clipBehavior, +}) { + return ClipRRectDecorator( + clipper: clipper, + clipBehavior: clipBehavior, + borderRadius: BorderRadius.circular(radius), + ); +} + +// ClipDecorator clipOval() => const ClipDecorator(ClipDecoratorType.oval); + +ClipDecorator clipTriangle({Clip? clipBehavior}) { + return ClipPathDecorator( + clipper: const TriangleClipper(), + clipBehavior: clipBehavior, + ); +} diff --git a/lib/src/utils/gradient_util.dart b/lib/src/utils/gradient_util.dart new file mode 100644 index 000000000..662030959 --- /dev/null +++ b/lib/src/utils/gradient_util.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +import '../attributes/scalar_attribute.dart'; + +GradientAttribute linearGradient({ + AlignmentGeometry? begin, + AlignmentGeometry? end, + required List colors, + List? stops, + TileMode? tileMode, + GradientTransform? transform, +}) { + final defaultGradient = LinearGradient(colors: colors); + + return GradientAttribute( + LinearGradient( + begin: begin ?? defaultGradient.begin, + end: end ?? defaultGradient.end, + colors: colors, + stops: stops, + tileMode: tileMode ?? defaultGradient.tileMode, + transform: transform, + ), + ); +} + +GradientAttribute radialGradient({ + AlignmentGeometry? center, + double? radius, + required List colors, + List? stops, + TileMode tileMode = TileMode.clamp, + AlignmentGeometry? focal, + double? focalRadius, + GradientTransform? transform, +}) { + final defaultGradient = RadialGradient(colors: colors); + + return GradientAttribute( + RadialGradient( + center: center ?? defaultGradient.center, + radius: radius ?? defaultGradient.radius, + colors: colors, + stops: stops, + tileMode: tileMode, + focal: focal, + focalRadius: focalRadius ?? defaultGradient.focalRadius, + transform: transform, + ), + ); +} diff --git a/lib/src/utils/helper_util.dart b/lib/src/utils/helper_util.dart new file mode 100644 index 000000000..d2d289b63 --- /dev/null +++ b/lib/src/utils/helper_util.dart @@ -0,0 +1,37 @@ +typedef FunctionWithParams = ReturnT Function( + Iterable params, +); + +class SpreadFunctionParams { + final FunctionWithParams fn; + + const SpreadFunctionParams(this.fn); + + ReturnT call([ + ParamT? p1, + ParamT? p2, + ParamT? p3, + ParamT? p4, + ParamT? p5, + ParamT? p6, + ParamT? p7, + ParamT? p8, + ParamT? p9, + ParamT? p10, + ParamT? p11, + ParamT? p12, + ParamT? p13, + ParamT? p14, + ParamT? p15, + ParamT? p16, + ParamT? p17, + ParamT? p18, + ParamT? p19, + ParamT? p20, + ]) { + return fn([ + p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, // + p12, p13, p14, p15, p16, p17, p18, p19, p20, + ].whereType()); + } +} diff --git a/lib/src/utils/pressable_util.dart b/lib/src/utils/pressable_util.dart new file mode 100644 index 000000000..ff819c292 --- /dev/null +++ b/lib/src/utils/pressable_util.dart @@ -0,0 +1,34 @@ +import 'package:flutter/material.dart'; + +import '../helpers/extensions/string_ext.dart'; +import '../variants/context_variant.dart'; +import '../widgets/pressable/pressable.notifier.dart'; +import '../widgets/pressable/pressable_state.dart'; +import 'context_variant_util.dart'; + +final onPress = _pressableVariant(PressableState.pressed); +final onLongPress = _pressableVariant(PressableState.longPressed); +final onHover = _pressableVariant(PressableState.hover); +final onDisabled = _pressableVariant(PressableState.disabled); + +final onEnabled = onNot(onDisabled); + +final onFocus = ContextVariant( + 'on-focus', + when: (BuildContext context) { + final pressable = PressableNotifier.of(context); + + return pressable?.focus == true; + }, +); + +ContextVariant _pressableVariant(PressableState state) { + return ContextVariant( + 'on-${state.name.paramCase}', + when: (BuildContext context) { + final pressable = PressableNotifier.of(context); + + return pressable?.state == state; + }, + ); +} diff --git a/lib/src/utils/scalar_util.dart b/lib/src/utils/scalar_util.dart new file mode 100644 index 000000000..b3c880f22 --- /dev/null +++ b/lib/src/utils/scalar_util.dart @@ -0,0 +1,55 @@ +import '../attributes/color_attribute.dart'; +import '../attributes/scalar_attribute.dart'; + +const visible = VisibleAttribute.new; + +const stackFit = StackFitAttribute.new; + +const clip = ClipAttribute.new; + +const transform = TransformAttribute.new; + +const verticalDirection = VerticalDirectionAttribute.new; + +const textDirection = TextDirectionAttribute.new; + +const softWrap = SoftWrapAttribute.new; + +const textOverflow = TextOverflowAttribute.new; + +const textScaleFactor = TextScaleFactorAttribute.new; + +const maxLines = MaxLinesAttribute.new; + +const textWidthBasis = TextWidthBasisAttribute.new; + +const textAlign = TextAlignAttribute.new; + +const flexFit = FlexFitAttribute.new; + +const axisDirection = AxisAttribute.new; + +const mainAxisAlignment = MainAxisAlignmentAttribute.new; + +const crossAxisAlignment = CrossAxisAlignmentAttribute.new; + +const mainAxisSize = MainAxisSizeAttribute.new; + +const iconSize = IconSizeAttribute.new; +const iconColor = IconColorAttribute.new; + +const gradient = GradientAttribute.new; +const transformAlignment = TransformAlignmentAttribute.new; +const textBaseline = TextBaselineAttribute.new; +const imageAlignment = ImageAlignmentAttribute.new; +const imageScale = ImageScaleAttribute.new; +const imageFit = ImageFitAttribute.new; +const imageRepeat = ImageRepeatAttribute.new; + +const imageWidth = ImageWidthAttribute.new; +const imageHeight = ImageHeightAttribute.new; +const textHeightBehavior = TextHeightBehaviorAttribute.new; +const boxFit = BoxFitAttribute.new; +const blendMode = BlendModeAttribute.new; +const boxShape = BoxShapeAttribute.new; +const imageColor = ImageColorAttribute.new; diff --git a/lib/src/utils/space_util.dart b/lib/src/utils/space_util.dart new file mode 100644 index 000000000..17873e597 --- /dev/null +++ b/lib/src/utils/space_util.dart @@ -0,0 +1,156 @@ +import 'package:flutter/material.dart'; + +import '../attributes/space_attribute.dart'; +import '../theme/tokens/space_token.dart'; + +const _paddingUtil = SpaceUtilityFactory(PaddingAttribute.new); +const _paddingDirectionalUtil = + SpaceDirectionalUtilityFactory(PaddingDirectionalAttribute.new); + +final padding = _paddingUtil.shorthand; +final paddingDirectional = _paddingDirectionalUtil.shorthand; +final paddingOnly = _paddingUtil.only; +final paddingDirectionalOnly = _paddingDirectionalUtil.only; +final paddingAll = UtilityWithSpaceTokens(_paddingUtil.all); +final paddingTop = UtilityWithSpaceTokens(_paddingUtil.top); +final paddingBottom = UtilityWithSpaceTokens(_paddingUtil.bottom); +final paddingLeft = UtilityWithSpaceTokens(_paddingUtil.left); +final paddingRight = UtilityWithSpaceTokens(_paddingUtil.right); +final paddingStart = UtilityWithSpaceTokens(_paddingDirectionalUtil.start); +final paddingEnd = UtilityWithSpaceTokens(_paddingDirectionalUtil.end); +final paddingHorizontal = UtilityWithSpaceTokens(_paddingUtil.horizontal); +final paddingVertical = UtilityWithSpaceTokens(_paddingUtil.vertical); + +PaddingGeometryAttribute paddingFrom(EdgeInsetsGeometry edgeInsets) { + if (edgeInsets is EdgeInsets) { + return _paddingUtil.from(edgeInsets); + } else if (edgeInsets is EdgeInsetsDirectional) { + return _paddingDirectionalUtil.from(edgeInsets); + } + throw UnimplementedError( + 'paddingFrom is not implemented for ${edgeInsets.runtimeType}', + ); +} + +const _marginUtil = SpaceUtilityFactory(MarginAttribute.new); +const _marginDirectionalUtil = + SpaceDirectionalUtilityFactory(MarginDirectionalAttribute.new); + +final margin = _marginUtil.shorthand; +final marginDirectional = _marginDirectionalUtil.shorthand; +final marginOnly = _marginUtil.only; +final marginDirectionalOnly = _marginDirectionalUtil.only; +final marginAll = UtilityWithSpaceTokens(_marginUtil.all); +final marginTop = UtilityWithSpaceTokens(_marginUtil.top); +final marginBottom = UtilityWithSpaceTokens(_marginUtil.bottom); +final marginLeft = UtilityWithSpaceTokens(_marginUtil.left); +final marginRight = UtilityWithSpaceTokens(_marginUtil.right); +final marginStart = UtilityWithSpaceTokens(_marginDirectionalUtil.start); +final marginEnd = UtilityWithSpaceTokens(_marginDirectionalUtil.end); +final marginHorizontal = UtilityWithSpaceTokens(_marginUtil.horizontal); +final marginVertical = UtilityWithSpaceTokens(_marginUtil.vertical); + +MarginGeometryAttribute marginFrom(EdgeInsetsGeometry edgeInsets) { + if (edgeInsets is EdgeInsets) { + return _marginUtil.from(edgeInsets); + } else if (edgeInsets is EdgeInsetsDirectional) { + return _marginDirectionalUtil.from(edgeInsets); + } + throw UnimplementedError( + 'marginFrom is not implemented for ${edgeInsets.runtimeType}', + ); +} + +typedef SpaceAttributeBuilder = T Function({ + double? top, + double? bottom, + double? left, + double? right, +}); + +@immutable +class SpaceUtilityFactory { + final SpaceAttributeBuilder _builder; + + const SpaceUtilityFactory(this._builder); + + SpaceAttributeBuilder get only => _builder; + + T all(double all) => _builder(bottom: all, left: all, right: all, top: all); + + T top(double value) => _builder(top: value); + T bottom(double value) => _builder(bottom: value); + T left(double value) => _builder(left: value); + T right(double value) => _builder(right: value); + + T horizontal(double value) => _builder(left: value, right: value); + T vertical(double value) => _builder(bottom: value, top: value); + + T from(EdgeInsets edgeInsets) { + return _builder( + bottom: edgeInsets.bottom, + left: edgeInsets.left, + right: edgeInsets.right, + top: edgeInsets.top, + ); + } + + T shorthand(double p1, [double? p2, double? p3, double? p4]) { + double top = p1; + double bottom = p1; + double left = p1; + double right = p1; + + if (p2 != null) { + left = p2; + right = p2; + } + + if (p3 != null) bottom = p3; + if (p4 != null) left = p4; + + return _builder(bottom: bottom, left: left, right: right, top: top); + } +} + +typedef SpaceDirectionalBuilder = T + Function({double? top, double? bottom, double? start, double? end}); + +@immutable +class SpaceDirectionalUtilityFactory { + final SpaceDirectionalBuilder _builder; + + const SpaceDirectionalUtilityFactory(this._builder); + + SpaceDirectionalBuilder get only => _builder; + + T start(double value) => _builder(start: value); + T end(double value) => _builder(end: value); + + T from(EdgeInsetsDirectional edgeInsets) { + return _builder( + bottom: edgeInsets.bottom, + end: edgeInsets.end, + start: edgeInsets.start, + top: edgeInsets.top, + ); + } + + T shorthand(double p1, [double? p2, double? p3, double? p4]) { + double top = p1; + double bottom = p1; + double start = p1; + double end = p1; + + if (p2 != null) { + start = p2; + end = p2; + } + + if (p3 != null) bottom = p3; + + if (p4 != null) start = p4; + + return _builder(bottom: bottom, end: end, start: start, top: top); + } +} diff --git a/lib/src/utils/text_directives_util.dart b/lib/src/utils/text_directives_util.dart new file mode 100644 index 000000000..060e48d13 --- /dev/null +++ b/lib/src/utils/text_directives_util.dart @@ -0,0 +1,8 @@ +import '../directives/text_directive.dart'; + +/// Directives. +const capitalize = CapitalizeDirective.new; +const upperCase = UppercaseDirective.new; +const lowerCase = LowercaseDirective.new; +const titleCase = TitleCaseDirective.new; +const sentenceCase = SentenceCaseDirective.new; diff --git a/lib/src/utils/text_util.dart b/lib/src/utils/text_util.dart new file mode 100644 index 000000000..e47fc18e2 --- /dev/null +++ b/lib/src/utils/text_util.dart @@ -0,0 +1,81 @@ +// ignore_for_file: long-parameter-list + +import 'dart:ui'; + +import 'package:flutter/material.dart'; + +import '../attributes/shadow_attribute.dart'; +import '../attributes/strut_style_attribute.dart'; +import '../attributes/text_style_attribute.dart'; +import '../directives/text_directive.dart'; +import '../helpers/extensions/values_ext.dart'; + +StrutStyleAttribute strutStyle(StrutStyle strutStyle) { + return strutStyle.toAttribute(); +} + +TextDirectiveAttribute textDirective(TextDirective directive) => + TextDirectiveAttribute([directive]); + +TextStyleAttribute textStyle({ + String? fontFamily, + FontWeight? fontWeight, + FontStyle? fontStyle, + double? fontSize, + double? letterSpacing, + double? wordSpacing, + TextBaseline? textBaseline, + List? shadows, + Color? color, + Color? backgroundColor, + List? fontFeatures, + TextDecoration? decoration, + Color? decorationColor, + TextDecorationStyle? decorationStyle, + Paint? foreground, + Paint? background, + String? debugLabel, + Locale? locale, + double? height, +}) { + return TextStyleAttribute( + background: background, + backgroundColor: backgroundColor?.toAttribute(), + color: color?.toAttribute(), + debugLabel: debugLabel, + decoration: decoration, + decorationColor: decorationColor?.toAttribute(), + decorationStyle: decorationStyle, + fontFamily: fontFamily, + fontFeatures: fontFeatures, + fontSize: fontSize, + fontStyle: fontStyle, + fontWeight: fontWeight, + foreground: foreground, + height: height, + letterSpacing: letterSpacing, + locale: locale, + shadows: _shadowsFromDto(shadows), + textBaseline: textBaseline, + wordSpacing: wordSpacing, + ); +} + +TextStyleAttribute bold() => textStyle(fontWeight: FontWeight.bold); + +TextStyleAttribute italic() => textStyle(fontStyle: FontStyle.italic); + +ShadowAttribute _shadowFromDto(Shadow shadow) { + return ShadowAttribute( + blurRadius: shadow.blurRadius, + color: shadow.color.toAttribute(), + offset: shadow.offset, + ); +} + +List? _shadowsFromDto(List? shadows) { + if (shadows == null) return null; + if (shadows.isEmpty) return []; + + return shadows.map(_shadowFromDto).toList(); +} diff --git a/lib/src/variants/context_variant.dart b/lib/src/variants/context_variant.dart index 60edce133..30cd4d293 100644 --- a/lib/src/variants/context_variant.dart +++ b/lib/src/variants/context_variant.dart @@ -1,64 +1,52 @@ -import 'package:flutter/material.dart'; - -import '../../mix.dart'; -import 'variant_attribute.dart'; - -typedef ShouldApplyFunc = bool Function(BuildContext); +import 'dart:core'; -@Deprecated( - 'Use ContextStyleVariant instead. ' - 'This class will be removed in a future release.', -) -typedef ContextVariant = ContextStyleVariant; +import 'package:flutter/material.dart'; -class ContextStyleVariant extends StyleVariant { - const ContextStyleVariant( - super.name, { - required ShouldApplyFunc shouldApply, - bool inverse = false, - }) : _inverse = inverse, - _shouldApply = shouldApply; +import '../attributes/attribute.dart'; +import '../attributes/variant_attribute.dart'; +import '../factory/style_mix.dart'; +import 'variant.dart'; - final bool _inverse; +typedef WhenContextFunction = bool Function(BuildContext context); - final ShouldApplyFunc _shouldApply; +@immutable +class ContextVariant extends Variant { + final WhenContextFunction when; - bool shouldApply(BuildContext context) { - return _inverse ? !_shouldApply(context) : _shouldApply(context); - } + const ContextVariant(super.name, {required this.when}); @override - // ignore: long-parameter-list ContextVariantAttribute call([ - StyleAttribute? p1, - StyleAttribute? p2, - StyleAttribute? p3, - StyleAttribute? p4, - StyleAttribute? p5, - StyleAttribute? p6, - StyleAttribute? p7, - StyleAttribute? p8, - StyleAttribute? p9, - StyleAttribute? p10, - StyleAttribute? p11, - StyleAttribute? p12, + Attribute? p1, + Attribute? p2, + Attribute? p3, + Attribute? p4, + Attribute? p5, + Attribute? p6, + Attribute? p7, + Attribute? p8, + Attribute? p9, + Attribute? p10, + Attribute? p11, + Attribute? p12, + Attribute? p13, + Attribute? p14, + Attribute? p15, + Attribute? p16, + Attribute? p17, + Attribute? p18, + Attribute? p19, + Attribute? p20, ]) { - final params = []; + final params = [ + p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, // + p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, + ].whereType(); - for (final param in [p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12]) { - if (param != null) params.add(param); - } - - return ContextVariantAttribute(this, StyleMix.fromAttributes(params)); - } - - ContextStyleVariant inverseInstance() { - return ContextStyleVariant( - name, - shouldApply: _shouldApply, - inverse: !_inverse, - ); + // Create a ContextVariantAttribute using the collected parameters. + return ContextVariantAttribute(this, StyleMix.create(params)); } - get props => [name, _inverse, _shouldApply]; -} \ No newline at end of file + @override + get props => [name, when]; +} diff --git a/lib/src/variants/exports.dart b/lib/src/variants/exports.dart deleted file mode 100644 index 39b7f5279..000000000 --- a/lib/src/variants/exports.dart +++ /dev/null @@ -1,2 +0,0 @@ -export 'utilities/context_variant_utilities.dart'; -export 'variant.dart'; diff --git a/lib/src/variants/multi_variant.dart b/lib/src/variants/multi_variant.dart new file mode 100644 index 000000000..d5b3fdc52 --- /dev/null +++ b/lib/src/variants/multi_variant.dart @@ -0,0 +1,101 @@ +import 'package:flutter/material.dart'; + +import '../attributes/attribute.dart'; +import '../attributes/variant_attribute.dart'; +import '../factory/style_mix.dart'; +import 'context_variant.dart'; +import 'variant.dart'; + +enum MultiVariantType { and, or } + +@immutable +class MultiVariant extends Variant { + final List variants; + final MultiVariantType type; + + const MultiVariant._(super.name, this.variants, {required this.type}); + + factory MultiVariant( + Iterable variants, { + MultiVariantType type = MultiVariantType.and, + }) { + final sortedVariants = variants.toList() + ..sort(((a, b) => a.name.compareTo(b.name))); + final combinedName = sortedVariants.map((e) => e.name).join('-'); + + return MultiVariant._(combinedName, sortedVariants, type: type); + } + + factory MultiVariant.and(Iterable variants) => MultiVariant( + variants, + ); + + factory MultiVariant.or(Iterable variants) => + MultiVariant(variants, type: MultiVariantType.or); + + // Remove all variants in given a list + Variant remove(Iterable variantsToRemove) { + final remainingVariants = + variants.where((e) => !variantsToRemove.contains(e)); + + return remainingVariants.length == 1 + ? remainingVariants.first + : MultiVariant(remainingVariants); + } + + bool matches(Iterable otherVariants) { + return type == MultiVariantType.and + ? variants.every(otherVariants.contains) + : variants.any(otherVariants.contains); + } + + bool when(BuildContext context) { + final contextVariants = variants.whereType(); + + bool matchContextVariant(ContextVariant variant) => variant.when(context); + + if (type == MultiVariantType.or) { + return contextVariants.any(matchContextVariant); + } + + // If all variants are context variants apply the context + return contextVariants.length == variants.length + ? contextVariants.every(matchContextVariant) + : false; + } + + @override + MultiVariantAttribute call([ + Attribute? p1, + Attribute? p2, + Attribute? p3, + Attribute? p4, + Attribute? p5, + Attribute? p6, + Attribute? p7, + Attribute? p8, + Attribute? p9, + Attribute? p10, + Attribute? p11, + Attribute? p12, + Attribute? p13, + Attribute? p14, + Attribute? p15, + Attribute? p16, + Attribute? p17, + Attribute? p18, + Attribute? p19, + Attribute? p20, + ]) { + final params = [ + p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, // + p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, + ].whereType(); + + // Create a ContextVariantAttribute using the collected parameters. + return MultiVariantAttribute(this, StyleMix.create(params)); + } + + @override + get props => [name, variants]; +} diff --git a/lib/src/variants/utilities/context_variant_utilities.dart b/lib/src/variants/utilities/context_variant_utilities.dart deleted file mode 100644 index a0314e64d..000000000 --- a/lib/src/variants/utilities/context_variant_utilities.dart +++ /dev/null @@ -1,152 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../../extensions/build_context_ext.dart'; -import '../../theme/mix_theme.dart'; -import '../../theme/tokens/breakpoints.dart'; -import '../../widgets/pressable/pressable.notifier.dart'; -import '../../widgets/pressable/pressable_state.dart'; -import '../context_variant.dart'; - -class ContextVariantUtilities { - const ContextVariantUtilities._(); - - static _screenSizeCheck(ScreenSizeToken screenSize) { - return (BuildContext context) { - final breakpoints = MixTheme.of(context).breakpoints; - - return breakpoints.getScreenSize(context).index <= screenSize.index; - }; - } - - static ContextStyleVariant onSmall() { - return ContextStyleVariant( - 'onSmall', - shouldApply: _screenSizeCheck(ScreenSizeToken.small), - ); - } - - static ContextStyleVariant onXsmall() { - return ContextStyleVariant( - 'onXsmall', - shouldApply: _screenSizeCheck(ScreenSizeToken.xsmall), - ); - } - - static ContextStyleVariant onMedium() { - return ContextStyleVariant( - 'onMedium', - shouldApply: _screenSizeCheck(ScreenSizeToken.medium), - ); - } - - static ContextStyleVariant onLarge() { - return ContextStyleVariant( - 'onLarge', - shouldApply: _screenSizeCheck(ScreenSizeToken.large), - ); - } - - static ContextStyleVariant onPortrait() { - return ContextStyleVariant( - 'onPortrait', - shouldApply: (BuildContext context) { - return context.orientation == Orientation.portrait; - }, - ); - } - - static ContextStyleVariant onLandscape() { - return ContextStyleVariant( - 'onLandscape', - shouldApply: (BuildContext context) { - return context.orientation == Orientation.landscape; - }, - ); - } - - static ContextStyleVariant onDark() { - return ContextStyleVariant( - 'onDark', - shouldApply: (BuildContext context) { - return context.isDarkMode; - }, - ); - } - - static ContextStyleVariant onLight() { - return ContextStyleVariant( - 'onLight', - shouldApply: (BuildContext context) { - return Theme.of(context).brightness == Brightness.light; - }, - ); - } - - static ContextStyleVariant onDisabled() { - return ContextStyleVariant( - 'onDisabled', - shouldApply: (BuildContext context) { - final pressable = PressableNotifier.of(context); - - return pressable?.state == PressableState.disabled; - }, - ); - } - - static ContextStyleVariant onFocus() { - return ContextStyleVariant( - 'onFocus', - shouldApply: (BuildContext context) { - final pressable = PressableNotifier.of(context); - - return pressable?.focus == true; - }, - ); - } - - static ContextStyleVariant onPress() { - return ContextStyleVariant( - 'onPress', - shouldApply: (BuildContext context) { - final pressable = PressableNotifier.of(context); - - return pressable?.state == PressableState.pressed; - }, - ); - } - - static ContextStyleVariant onLongPress() { - return ContextStyleVariant( - 'onLongPress', - shouldApply: (BuildContext context) { - final pressable = PressableNotifier.of(context); - - return pressable?.state == PressableState.longPressed; - }, - ); - } - - static ContextStyleVariant onHover() { - return ContextStyleVariant( - 'onHover', - shouldApply: (BuildContext context) { - final pressable = PressableNotifier.of(context); - - return pressable?.state == PressableState.hover; - }, - ); - } - - static T onNot(T other) { - return other.inverseInstance() as T; - } - - static ContextStyleVariant onRTL() { - return ContextStyleVariant( - 'onRTL', - shouldApply: (BuildContext context) { - return context.directionality == TextDirection.rtl; - }, - ); - } -} diff --git a/lib/src/variants/variant.dart b/lib/src/variants/variant.dart index 5f47a2bd1..0c56ea979 100644 --- a/lib/src/variants/variant.dart +++ b/lib/src/variants/variant.dart @@ -1,69 +1,61 @@ +import 'package:flutter/material.dart'; + import '../attributes/attribute.dart'; +import '../attributes/variant_attribute.dart'; +import '../core/equality/compare_mixin.dart'; import '../factory/style_mix.dart'; -import 'variant_attribute.dart'; -import 'variant_operation.dart'; - -@Deprecated( - 'Use StyleVariant instead. ' - 'This class will be removed in a future release.', -) -typedef Variant = StyleVariant; +import 'multi_variant.dart'; /// A class representing a variant, which is a combination of attributes. /// It can be combined with other variants using logical AND (&) and OR (|) operations. -class StyleVariant { +@immutable +class Variant with Comparable { final String name; - /// Creates a new [StyleVariant] with a given [name] and an optional [inverse] flag. - const StyleVariant(this.name); + /// Creates a new [Variant] with a given [name] and an optional [inverse] flag. + const Variant(this.name); /// Combines this variant with another [variant] using a logical AND operation. - VariantOperation operator &(StyleVariant variant) { - return VariantOperation([this, variant], operator: EnumVariantOperator.and); - } + MultiVariant operator &(Variant variant) => MultiVariant.and([this, variant]); /// Combines this variant with another [variant] using a logical OR operation. - VariantOperation operator |(StyleVariant variant) { - return VariantOperation([this, variant], operator: EnumVariantOperator.or); - } + MultiVariant operator |(Variant variant) => MultiVariant.or([this, variant]); /// Applies the variant to a set of attributes and creates a [VariantAttribute] instance. - /// Up to 12 optional [StyleAttribute] parameters can be provided. - // ignore: long-parameter-list + /// Up to 12 optional [Attribute] parameters can be provided. + VariantAttribute call([ - StyleAttribute? p1, - StyleAttribute? p2, - StyleAttribute? p3, - StyleAttribute? p4, - StyleAttribute? p5, - StyleAttribute? p6, - StyleAttribute? p7, - StyleAttribute? p8, - StyleAttribute? p9, - StyleAttribute? p10, - StyleAttribute? p11, - StyleAttribute? p12, + Attribute? p1, + Attribute? p2, + Attribute? p3, + Attribute? p4, + Attribute? p5, + Attribute? p6, + Attribute? p7, + Attribute? p8, + Attribute? p9, + Attribute? p10, + Attribute? p11, + Attribute? p12, + Attribute? p13, + Attribute? p14, + Attribute? p15, + Attribute? p16, + Attribute? p17, + Attribute? p18, + Attribute? p19, + Attribute? p20, ]) { - final params = []; + final params = [ + p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, // + p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, + ].whereType(); - for (final param in [p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12]) { - if (param != null) params.add(param); - } + // Create a VariantAttribute using the collected parameters. - // Create a VariantAttribute using the collected parameters - return VariantAttribute(this, StyleMix.fromAttributes(params)); + return VariantAttribute(this, StyleMix.create(params)); } @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - - return other is StyleVariant && other.name == name; - } - - @override - int get hashCode => name.hashCode; - - @override - String toString() => 'name: $name'; + get props => [name]; } diff --git a/lib/src/variants/variant_attribute.dart b/lib/src/variants/variant_attribute.dart deleted file mode 100644 index f2b4998de..000000000 --- a/lib/src/variants/variant_attribute.dart +++ /dev/null @@ -1,64 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../attributes/attribute.dart'; -import '../factory/style_mix.dart'; -import 'context_variant.dart'; -import 'variant.dart'; - -class VariantAttribute extends StyleAttribute - with Mergeable> { - const VariantAttribute( - this.variant, - StyleMix style, - ) : _style = style; - - final T variant; - final StyleMix _style; - - StyleMix get value => _style; - - @override - VariantAttribute merge(covariant VariantAttribute other) { - if (other.variant != variant) { - throw ArgumentError.value( - other, - 'other', - 'VariantAttribute must have the same variant', - ); - } - - return VariantAttribute( - variant, - _style.merge(other._style), - ); - } - - @override - String toString() => 'VariantAttribute(variant: $variant, mix: $value)'; - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - - return other is VariantAttribute && - other.variant == variant && - other.value == value; - } - - @override - int get hashCode => variant.hashCode ^ _style.hashCode; - - @override - get props => [variant, value]; -} - -class ContextVariantAttribute extends VariantAttribute { - const ContextVariantAttribute( - super.variant, - super.style, - ); - - bool shouldApply(BuildContext context) { - return variant.shouldApply.call(context); - } -} diff --git a/lib/src/variants/variant_operation.dart b/lib/src/variants/variant_operation.dart deleted file mode 100644 index f7ca5f868..000000000 --- a/lib/src/variants/variant_operation.dart +++ /dev/null @@ -1,120 +0,0 @@ -import 'package:flutter/foundation.dart'; - -import '../attributes/attribute.dart'; -import '../attributes/nested_attribute.dart'; -import '../factory/style_mix.dart'; -import 'context_variant.dart'; -import 'variant.dart'; -import 'variant_attribute.dart'; - -enum EnumVariantOperator { and, or } - -class VariantOperation { - final List variants; - final EnumVariantOperator operator; - - const VariantOperation( - this.variants, { - required this.operator, - }); - - VariantOperation operator &(StyleVariant variant) { - if (operator != EnumVariantOperator.and) { - throw ArgumentError('All the operators in the equation must be the same'); - } - - variants.add(variant); - - return this; - } - - VariantOperation operator |(StyleVariant variant) { - if (operator != EnumVariantOperator.or) { - throw ArgumentError('All the operators in the equation must be the same'); - } - - variants.add(variant); - - return this; - } - - List _buildOrOperations( - List attributes, { - Iterable? variants, - }) { - variants ??= this.variants; - final style = StyleMix.fromAttributes(attributes); - final attributeVariants = variants.map((variant) { - return variant is ContextStyleVariant - ? ContextVariantAttribute(variant, style) - : VariantAttribute(variant, style); - }); - - return attributeVariants.toList(); - } - - List _buildAndOperations( - List attributes, - ) { - final attributeVariants = variants.map((variant) { - final otherVariants = variants.where((otherV) => otherV != variant); - final mixToApply = StyleMix.fromAttributes( - _buildOrOperations( - attributes, - variants: otherVariants, - ), - ); - - return variant is ContextStyleVariant - ? ContextVariantAttribute(variant, mixToApply) - : VariantAttribute(variant, mixToApply); - }); - - return attributeVariants.toList(); - } - - // ignore: long-parameter-list - NestedStyleAttribute call([ - StyleAttribute? p1, - StyleAttribute? p2, - StyleAttribute? p3, - StyleAttribute? p4, - StyleAttribute? p5, - StyleAttribute? p6, - StyleAttribute? p7, - StyleAttribute? p8, - StyleAttribute? p9, - StyleAttribute? p10, - StyleAttribute? p11, - StyleAttribute? p12, - ]) { - final params = []; - for (final param in [p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12]) { - if (param != null) params.add(param); - } - - List attributes = []; - if (operator == EnumVariantOperator.and) { - attributes = _buildAndOperations(params); - } else if (operator == EnumVariantOperator.or) { - attributes = _buildOrOperations(params); - } - - return NestedStyleAttribute(StyleMix.fromAttributes(attributes)); - } - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - - return other is VariantOperation && - listEquals(other.variants, variants) && - other.operator == operator; - } - - @override - int get hashCode => variants.hashCode ^ operator.hashCode; - - @override - String toString() => 'MultiVariant(variants: $variants, operator: $operator)'; -} diff --git a/lib/src/widgets/container/container.attributes.dart b/lib/src/widgets/container/container.attributes.dart deleted file mode 100644 index 593936cf4..000000000 --- a/lib/src/widgets/container/container.attributes.dart +++ /dev/null @@ -1,185 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../../attributes/attribute.dart'; -import '../../dtos/border/box_border.dto.dart'; -import '../../dtos/color.dto.dart'; -import '../../dtos/edge_insets/edge_insets_geometry.dto.dart'; -import '../../dtos/radius/border_radius_geometry.dto.dart'; -import '../../dtos/shadow/box_shadow.dto.dart'; -import '../../extensions/helper_ext.dart'; - -@Deprecated('Use ContainerStyleAttributes instead') -typedef BoxAttributes = StyledContainerAttributes; - -class StyledContainerAttributes extends StyledWidgetAttributes { - final EdgeInsetsGeometryDto? margin; - final EdgeInsetsGeometryDto? padding; - final AlignmentGeometry? alignment; - final double? height; - final double? width; - // Decoration - final ColorDto? color; - final BoxBorderDto? border; - final BorderRadiusGeometryDto? borderRadius; - final List? boxShadow; - final Matrix4? transform; - - // Constraints - final double? maxHeight; - final double? minHeight; - final double? maxWidth; - final double? minWidth; - final BoxShape? shape; - final Gradient? gradient; - - const StyledContainerAttributes({ - this.margin, - this.padding, - this.alignment, - this.border, - this.borderRadius, - this.color, - this.boxShadow, - this.height, - this.width, - this.maxHeight, - this.minHeight, - this.maxWidth, - this.minWidth, - this.shape, - this.transform, - this.gradient, - }); - - @override - StyledContainerAttributes copyWith({ - EdgeInsetsGeometryDto? margin, - EdgeInsetsGeometryDto? padding, - AlignmentGeometry? alignment, - ColorDto? color, - BoxBorderDto? border, - BorderRadiusGeometryDto? borderRadius, - List? boxShadow, - Matrix4? transform, - double? height, - double? width, - double? maxHeight, - double? minHeight, - double? maxWidth, - double? minWidth, - BoxShape? shape, - Gradient? gradient, - }) { - return StyledContainerAttributes( - // Mergeble values - border: this.border?.merge(border) ?? border, - borderRadius: this.borderRadius?.merge(borderRadius) ?? borderRadius, - boxShadow: this.boxShadow?.merge(boxShadow) ?? boxShadow, - margin: this.margin?.merge(margin) ?? margin, - padding: this.padding?.merge(padding) ?? padding, - transform: this.transform?.merge(transform) ?? transform, - - // Override values - alignment: alignment ?? this.alignment, - color: color ?? this.color, - height: height ?? this.height, - maxHeight: maxHeight ?? this.maxHeight, - minHeight: minHeight ?? this.minHeight, - - width: width ?? this.width, - maxWidth: maxWidth ?? this.maxWidth, - minWidth: minWidth ?? this.minWidth, - shape: shape ?? this.shape, - gradient: gradient ?? this.gradient, - ); - } - - factory StyledContainerAttributes.from({ - EdgeInsetsGeometry? margin, - EdgeInsetsGeometry? padding, - AlignmentGeometry? alignment, - double? height, - double? width, - // Decoration - Color? color, - BoxBorder? border, - BorderRadiusGeometry? borderRadius, - List? boxShadow, - Matrix4? transform, - - // Constraints - double? maxHeight, - double? minHeight, - double? maxWidth, - double? minWidth, - BoxShape? shape, - Gradient? gradient, - }) { - return StyledContainerAttributes( - margin: EdgeInsetsGeometryDto.maybeFrom(margin), - padding: EdgeInsetsGeometryDto.maybeFrom(padding), - alignment: alignment, - height: height, - width: width, - // Decoration - color: ColorDto.maybeFrom(color), - border: BoxBorderDto.maybeFrom(border), - borderRadius: BorderRadiusGeometryDto.maybeFrom(borderRadius), - boxShadow: boxShadow, - transform: transform, - // Constraints - maxHeight: maxHeight, - minHeight: minHeight, - maxWidth: maxWidth, - minWidth: minWidth, - shape: shape, - gradient: gradient, - ); - } - - @override - StyledContainerAttributes merge(StyledContainerAttributes? other) { - if (other == null) return this; - - return copyWith( - // Mergeble values - border: other.border, - borderRadius: other.borderRadius, - boxShadow: other.boxShadow, - margin: other.margin, - padding: other.padding, - transform: other.transform, - // Override values - alignment: other.alignment, - color: other.color, - height: other.height, - maxHeight: other.maxHeight, - minHeight: other.minHeight, - width: other.width, - maxWidth: other.maxWidth, - minWidth: other.minWidth, - shape: other.shape, - gradient: other.gradient, - ); - } - - @override - get props => [ - margin, - padding, - alignment, - height, - width, - color, - border, - borderRadius, - boxShadow, - transform, - maxHeight, - minHeight, - maxWidth, - minWidth, - shape, - gradient, - ]; -} diff --git a/lib/src/widgets/container/container.descriptor.dart b/lib/src/widgets/container/container.descriptor.dart deleted file mode 100644 index 6ad9bd387..000000000 --- a/lib/src/widgets/container/container.descriptor.dart +++ /dev/null @@ -1,145 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../../../mix.dart'; -import '../../dtos/shadow/box_shadow.dto.dart'; -import '../../helpers/equality_mixin/equality_mixin.dart'; - -class StyledContainerDescriptor with EqualityMixin { - final Color? _color; - final AlignmentGeometry? alignment; - final EdgeInsetsGeometry? padding; - final EdgeInsetsGeometry? margin; - final double? width; - final double? height; - - final BoxBorder? border; - final BorderRadiusGeometry? borderRadius; - final List? boxShadow; - final Matrix4? transform; - final Gradient? gradient; - - // Constraints - final double? maxHeight; - - final double? minHeight; - final double? maxWidth; - final double? minWidth; - final BoxShape? shape; - - const StyledContainerDescriptor({ - Color? color, - this.alignment, - this.padding, - this.margin, - this.width, - this.height, - this.border, - this.borderRadius, - this.boxShadow, - this.maxHeight, - this.minHeight, - this.maxWidth, - this.minWidth, - this.shape, - this.transform, - this.gradient, - }) : _color = color; - - factory StyledContainerDescriptor.fromContext(MixData mix) { - final attributes = mix.attributesOfType(); - - return StyledContainerDescriptor( - color: attributes?.color?.resolve(mix), - alignment: attributes?.alignment, - margin: attributes?.margin?.resolve(mix), - padding: attributes?.padding?.resolve(mix), - width: attributes?.width, - height: attributes?.height, - border: attributes?.border?.resolve(mix), - borderRadius: attributes?.borderRadius?.resolve(mix), - boxShadow: attributes?.boxShadow?.resolve(mix), - maxHeight: attributes?.maxHeight, - maxWidth: attributes?.maxWidth, - minHeight: attributes?.minHeight, - minWidth: attributes?.minWidth, - shape: attributes?.shape, - transform: attributes?.transform, - gradient: attributes?.gradient, - ); - } - - // Color is null decoration exists, color gets added to decoration - Color? get color => decoration == null ? _color : null; - - BoxDecoration? get decoration { - BoxDecoration? boxDecoration; - if (border != null || - borderRadius != null || - boxShadow != null || - shape != null || - gradient != null) { - boxDecoration = BoxDecoration( - color: _color, - border: border, - boxShadow: boxShadow, - gradient: gradient, - ); - - // Shape is added separately because it doesn't accept a nullable value - if (shape != null) { - boxDecoration = boxDecoration.copyWith( - shape: shape, - ); - } - - // Border radius is added if no shape exists. - if (shape == null && borderRadius != null) { - boxDecoration = boxDecoration.copyWith( - borderRadius: borderRadius, - ); - } - - return boxDecoration; - } else { - return null; - } - } - - BoxConstraints? get constraints { - BoxConstraints? constraints; - - if (minWidth != null || - maxWidth != null || - minHeight != null || - maxHeight != null) { - constraints = BoxConstraints( - minHeight: minHeight ?? 0.0, - maxHeight: maxHeight ?? double.infinity, - minWidth: minWidth ?? 0.0, - maxWidth: maxWidth ?? double.infinity, - ); - } - - return constraints; - } - - @override - get props => [ - _color, - alignment, - padding, - margin, - width, - height, - border, - borderRadius, - boxShadow, - maxHeight, - minHeight, - maxWidth, - minWidth, - shape, - transform, - gradient, - ]; -} diff --git a/lib/src/widgets/container/container.utilities.dart b/lib/src/widgets/container/container.utilities.dart deleted file mode 100644 index 57510eee1..000000000 --- a/lib/src/widgets/container/container.utilities.dart +++ /dev/null @@ -1,769 +0,0 @@ -import 'package:flutter/material.dart'; - -import './container.attributes.dart'; -import '../../dtos/border/border.dto.dart'; -import '../../dtos/border/border_side.dto.dart'; -import '../../dtos/border/box_border.dto.dart'; -import '../../dtos/color.dto.dart'; -import '../../dtos/edge_insets/edge_insets.dto.dart'; -import '../../dtos/edge_insets/edge_insets_directional.dto.dart'; -import '../../dtos/edge_insets/edge_insets_geometry.dto.dart'; -import '../../dtos/radius/border_radius.dto.dart'; -import '../../dtos/radius/border_radius_directional.dto.dart'; -import '../../dtos/radius/border_radius_geometry.dto.dart'; -import '../../dtos/radius/radius_dto.dart'; -import '../../dtos/shadow/box_shadow.dto.dart'; - -class ContainerStyleUtilities { - StyledContainerAttributes margin(double value) { - return StyledContainerAttributes( - margin: EdgeInsetsDto.only( - top: value, - bottom: value, - left: value, - right: value, - ), - ); - } - - StyledContainerAttributes marginOnly({ - double? top, - double? bottom, - double? left, - double? right, - }) { - return StyledContainerAttributes( - margin: EdgeInsetsDto.only( - top: top, - bottom: bottom, - left: left, - right: right, - ), - ); - } - - StyledContainerAttributes marginInsets(EdgeInsetsGeometry insets) { - return StyledContainerAttributes( - margin: EdgeInsetsGeometryDto.from(insets), - ); - } - - StyledContainerAttributes marginSymmetric({ - double? vertical, - double? horizontal, - }) { - return StyledContainerAttributes( - margin: EdgeInsetsDto.symmetric( - vertical: vertical, - horizontal: horizontal, - ), - ); - } - - StyledContainerAttributes marginHorizontal(double value) { - return marginSymmetric(horizontal: value); - } - - StyledContainerAttributes marginVertical(double value) { - return marginSymmetric(vertical: value); - } - - StyledContainerAttributes marginTop(double value) { - return StyledContainerAttributes( - margin: EdgeInsetsDto.only(top: value), - ); - } - - StyledContainerAttributes marginRight(double value) { - return StyledContainerAttributes(margin: EdgeInsetsDto.only(right: value)); - } - - StyledContainerAttributes marginBottom(double value) { - return StyledContainerAttributes(margin: EdgeInsetsDto.only(bottom: value)); - } - - StyledContainerAttributes marginLeft(double value) { - return StyledContainerAttributes(margin: EdgeInsetsDto.only(left: value)); - } - - StyledContainerAttributes marginDirectionalStart(double value) { - return StyledContainerAttributes( - margin: EdgeInsetsDirectionalDto.only(start: value), - ); - } - - StyledContainerAttributes marginDirectionalEnd(double value) { - return StyledContainerAttributes( - margin: EdgeInsetsDirectionalDto.only(end: value), - ); - } - - StyledContainerAttributes marginDirectionalTop(double value) { - return StyledContainerAttributes( - margin: EdgeInsetsDirectionalDto.only(top: value), - ); - } - - StyledContainerAttributes marginDirectionalBottom(double value) { - return StyledContainerAttributes( - margin: EdgeInsetsDirectionalDto.only(bottom: value), - ); - } - - StyledContainerAttributes padding(double value) { - return StyledContainerAttributes(padding: EdgeInsetsDto.all(value)); - } - - StyledContainerAttributes paddingAll(double value) { - return StyledContainerAttributes(padding: EdgeInsetsDto.all(value)); - } - - StyledContainerAttributes paddingOnly( - double top, - double right, - double bottom, - double left, - ) { - return StyledContainerAttributes( - padding: EdgeInsetsDto.only( - top: top, - right: right, - bottom: bottom, - left: left, - ), - ); - } - - StyledContainerAttributes paddingSymmetric({ - double? vertical, - double? horizontal, - }) { - return StyledContainerAttributes( - padding: EdgeInsetsDto.symmetric( - vertical: vertical, - horizontal: horizontal, - ), - ); - } - - StyledContainerAttributes paddingInsets(EdgeInsetsGeometry insets) { - return StyledContainerAttributes( - padding: EdgeInsetsGeometryDto.from(insets),); - } - - StyledContainerAttributes paddingTop(double value) { - return StyledContainerAttributes(padding: EdgeInsetsDto.only(top: value)); - } - - StyledContainerAttributes paddingRight(double value) { - return StyledContainerAttributes(padding: EdgeInsetsDto.only(right: value)); - } - - StyledContainerAttributes paddingBottom(double value) { - return StyledContainerAttributes( - padding: EdgeInsetsDto.only(bottom: value), - ); - } - - StyledContainerAttributes paddingLeft(double value) { - return StyledContainerAttributes(padding: EdgeInsetsDto.only(left: value)); - } - - StyledContainerAttributes paddingHorizontal(double value) { - return StyledContainerAttributes( - padding: EdgeInsetsDto.symmetric( - horizontal: value, - ), - ); - } - - StyledContainerAttributes paddingVertical(double value) { - return StyledContainerAttributes( - padding: EdgeInsetsDto.symmetric( - vertical: value, - ), - ); - } - - StyledContainerAttributes paddingDirectionalOnly({ - double? top, - double? bottom, - double? start, - double? end, - }) { - return StyledContainerAttributes( - padding: EdgeInsetsDirectionalDto.only( - top: top, - bottom: bottom, - start: start, - end: end, - ), - ); - } - - StyledContainerAttributes paddingDirectionalStart(double value) { - return paddingDirectionalOnly(start: value); - } - - StyledContainerAttributes paddingDirectionalEnd(double value) { - return paddingDirectionalOnly(end: value); - } - - StyledContainerAttributes paddingDirectionalTop(double value) { - return paddingDirectionalOnly(top: value); - } - - StyledContainerAttributes paddingDirectionalBottom(double value) { - return paddingDirectionalOnly(bottom: value); - } - - StyledContainerAttributes backgroundColor(Color color) { - return StyledContainerAttributes( - color: ColorDto.from(color), - ); - } - - StyledContainerAttributes height(double height) { - return StyledContainerAttributes( - height: height, - ); - } - - StyledContainerAttributes width(double width) { - return StyledContainerAttributes( - width: width, - ); - } - - StyledContainerAttributes maxHeight(double maxHeight) { - return StyledContainerAttributes( - maxHeight: maxHeight, - ); - } - - StyledContainerAttributes maxWidth(double maxWidth) { - return StyledContainerAttributes( - maxWidth: maxWidth, - ); - } - - StyledContainerAttributes minHeight(double minHeight) { - return StyledContainerAttributes( - minHeight: minHeight, - ); - } - - StyledContainerAttributes minWidth(double minWidth) { - return StyledContainerAttributes( - minWidth: minWidth, - ); - } - - StyledContainerAttributes _borderRadius(BorderRadiusGeometryDto radius) { - return StyledContainerAttributes(borderRadius: radius); - } - - StyledContainerAttributes rounded(double value) { - return _borderRadius( - BorderRadiusDto.all( - RadiusDto.circular(value), - ), - ); - } - - StyledContainerAttributes squared() { - return _borderRadius(BorderRadiusDto.zero); - } - - StyledContainerAttributes roundedOnly({ - double? topLeft, - double? topRight, - double? bottomLeft, - double? bottomRight, - }) { - return _borderRadius( - BorderRadiusDto.only( - topLeft: topLeft != null ? RadiusDto.circular(topLeft) : null, - topRight: topRight != null ? RadiusDto.circular(topRight) : null, - bottomLeft: bottomLeft != null ? RadiusDto.circular(bottomLeft) : null, - bottomRight: - bottomRight != null ? RadiusDto.circular(bottomRight) : null, - ), - ); - } - - StyledContainerAttributes roundedDirectionalOnly({ - double? topStart, - double? topEnd, - double? bottomStart, - double? bottomEnd, - }) { - return _borderRadius( - BorderRadiusDirectionalDto.only( - topStart: topStart != null ? RadiusDto.circular(topStart) : null, - topEnd: topEnd != null ? RadiusDto.circular(topEnd) : null, - bottomStart: - bottomStart != null ? RadiusDto.circular(bottomStart) : null, - bottomEnd: bottomEnd != null ? RadiusDto.circular(bottomEnd) : null, - ), - ); - } - - StyledContainerAttributes roundedHorizontal({ - double? left, - double? right, - }) { - return _borderRadius( - BorderRadiusDto.horizontal( - left: left != null ? RadiusDto.circular(left) : null, - right: right != null ? RadiusDto.circular(right) : null, - ), - ); - } - - StyledContainerAttributes roundedVertical({ - double? top, - double? bottom, - }) { - return _borderRadius( - BorderRadiusDto.vertical( - top: top != null ? RadiusDto.circular(top) : null, - bottom: bottom != null ? RadiusDto.circular(bottom) : null, - ), - ); - } - - StyledContainerAttributes roundedDirectionalHorizontal({ - double? start, - double? end, - }) { - return _borderRadius( - BorderRadiusDirectionalDto.horizontal( - start: start != null ? RadiusDto.circular(start) : null, - end: end != null ? RadiusDto.circular(end) : null, - ), - ); - } - - StyledContainerAttributes roundedDirectionalVertical({ - double? top, - double? bottom, - }) { - return _borderRadius( - BorderRadiusDirectionalDto.vertical( - top: top != null ? RadiusDto.circular(top) : null, - bottom: bottom != null ? RadiusDto.circular(bottom) : null, - ), - ); - } - - BorderSideDto _borderSide({ - Color? color, - double? width, - BorderStyle? style, - BorderSide? as, - }) { - if (as != null) { - return BorderSideDto.from(as); - } else { - return BorderSideDto.only( - color: ColorDto.maybeFrom(color), - width: width, - style: style, - ); - } - } - - StyledContainerAttributes border({ - Color? color, - double? width, - BorderStyle? style, - // If you want to use a custom border, use [asBorder] instead - // This will ignore [color], [width] and [style] - BoxBorder? as, - }) { - BoxBorderDto border; - - if (as != null) { - border = BoxBorderDto.from(as); - } else { - border = BorderDto.all( - color: ColorDto.maybeFrom(color), - width: width, - style: style, - ); - } - - return StyledContainerAttributes(border: border); - } - - StyledContainerAttributes borderTop({ - Color? color, - double? width, - BorderStyle? style, - BorderSide? as, - }) { - return StyledContainerAttributes( - border: BorderDto.only( - top: _borderSide( - color: color, - width: width, - style: style, - ), - ), - ); - } - - StyledContainerAttributes borderBottom({ - Color? color, - double? width, - BorderStyle? style, - BorderSide? as, - }) { - return StyledContainerAttributes( - border: BorderDto.only( - bottom: _borderSide( - color: color, - width: width, - style: style, - ), - ), - ); - } - - StyledContainerAttributes borderLeft({ - Color? color, - double? width, - BorderStyle? style, - BorderSide? as, - }) { - return StyledContainerAttributes( - border: BorderDto.only( - left: _borderSide( - color: color, - width: width, - style: style, - as: as, - ), - ), - ); - } - - StyledContainerAttributes borderRight({ - Color? color, - double? width, - BorderStyle? style, - BorderSide? as, - }) { - return StyledContainerAttributes( - border: BorderDto.only( - right: _borderSide( - color: color, - width: width, - style: style, - as: as, - ), - ), - ); - } - - StyledContainerAttributes borderHorizontal({ - Color? color, - double? width, - BorderStyle? style, - BorderSide? as, - }) { - return StyledContainerAttributes( - border: BorderDto.symmetric( - horizontal: _borderSide( - color: color, - width: width, - style: style, - as: as, - ), - ), - ); - } - - StyledContainerAttributes borderVertical({ - Color? color, - double? width, - BorderStyle? style, - BorderSide? as, - }) { - return StyledContainerAttributes( - border: BorderDto.symmetric( - vertical: _borderSide( - color: color, - width: width, - style: style, - as: as, - ), - ), - ); - } - - StyledContainerAttributes borderDirectionalTop({ - Color? color, - double? width, - BorderStyle? style, - BorderSide? as, - }) { - return StyledContainerAttributes( - border: BorderDirectionalDto.only( - top: _borderSide( - color: color, - width: width, - style: style, - as: as, - ), - ), - ); - } - - StyledContainerAttributes borderDirectionalBottom({ - Color? color, - double? width, - BorderStyle? style, - BorderSide? as, - }) { - return StyledContainerAttributes( - border: BorderDirectionalDto.only( - bottom: _borderSide( - color: color, - width: width, - style: style, - as: as, - ), - ), - ); - } - - StyledContainerAttributes borderDirectionalStart({ - Color? color, - double? width, - BorderStyle? style, - BorderSide? as, - }) { - return StyledContainerAttributes( - border: BorderDirectionalDto.only( - start: _borderSide( - color: color, - width: width, - style: style, - as: as, - ), - ), - ); - } - - StyledContainerAttributes borderDirectionalEnd({ - Color? color, - double? width, - BorderStyle? style, - BorderSide? as, - }) { - return StyledContainerAttributes( - border: BorderDirectionalDto.only( - end: _borderSide( - color: color, - width: width, - style: style, - as: as, - ), - ), - ); - } - - StyledContainerAttributes transform(Matrix4 transform) { - return StyledContainerAttributes(transform: transform); - } - - StyledContainerAttributes alignment(AlignmentGeometry align) { - return StyledContainerAttributes(alignment: align); - } - - // ignore: long-parameter-list - StyledContainerAttributes linearGradient({ - AlignmentGeometry begin = AlignmentDirectional.centerStart, - AlignmentGeometry end = AlignmentDirectional.centerEnd, - required List colors, - List? stops, - TileMode tileMode = TileMode.clamp, - GradientTransform? transform, - }) { - return StyledContainerAttributes( - gradient: LinearGradient( - begin: begin, - end: end, - colors: colors, - stops: stops, - tileMode: tileMode, - transform: transform, - ), - ); - } - - // ignore: long-parameter-list - StyledContainerAttributes radialGradient({ - AlignmentGeometry center = Alignment.center, - double radius = 0.5, - required List colors, - List? stops, - TileMode tileMode = TileMode.clamp, - AlignmentGeometry? focal, - double focalRadius = 0.0, - GradientTransform? transform, - }) { - return StyledContainerAttributes( - gradient: RadialGradient( - center: center, - radius: radius, - colors: colors, - stops: stops, - tileMode: tileMode, - focal: focal, - focalRadius: focalRadius, - transform: transform, - ), - ); - } - - StyledContainerAttributes shadow({ - Color? color, - Offset? offset, - double? blurRadius, - double? spreadRadius, - }) { - final boxShadow = BoxShadowDto( - color: ColorDto.maybeFrom(color), - offset: offset, - blurRadius: blurRadius, - spreadRadius: spreadRadius, - ); - - return StyledContainerAttributes( - boxShadow: [boxShadow], - ); - } - - StyledContainerAttributes elevation(int elevation) { - const elevationOptions = [0, 1, 2, 3, 4, 6, 8, 9, 12, 16, 24]; - assert( - elevationOptions.contains(elevation), - 'Elevation must be one of the following: ${elevationOptions.join(', ')}', - ); - - const boxShadow = BoxShadowDto( - blurRadius: 0, - offset: Offset(0, 0), - spreadRadius: 0, - color: ColorDto(Colors.transparent), - ); - - if (elevation == 0) { - return const StyledContainerAttributes( - boxShadow: [boxShadow, boxShadow, boxShadow, boxShadow], - ); - } - - return StyledContainerAttributes( - boxShadow: kElevationToShadow[elevation]! - .map((e) => BoxShadowDto.fromBoxShadow(e)) - .toList(), - ); - } - - @Deprecated('Use border(color:color) instead') - StyledContainerAttributes borderColor(Color color) { - return StyledContainerAttributes( - border: BorderDto.all( - color: ColorDto.maybeFrom(color), - ), - ); - } - - @Deprecated('Use border(width:width) instead') - StyledContainerAttributes borderWidth(double width) { - return StyledContainerAttributes(border: BorderDto.all(width: width)); - } - - @Deprecated('Use border(style:style) instead') - StyledContainerAttributes borderStyle(BorderStyle style) { - return StyledContainerAttributes(border: BorderDto.all(style: style)); - } - - @Deprecated('Use backgroundColor(style:style) instead') - StyledContainerAttributes bgColor(Color color) { - return StyledContainerAttributes( - color: ColorDto.from(color), - ); - } - - @Deprecated('Use alignment instead') - StyledContainerAttributes align(AlignmentGeometry align) { - return StyledContainerAttributes(alignment: align); - } - - @Deprecated('Use borderDirectionalEnd instead') - StyledContainerAttributes borderEnd({ - Color? color, - double? width, - BorderStyle? style, - }) { - return borderDirectionalEnd( - color: color, - width: width, - style: style, - ); - } - - @Deprecated('Use borderDirectionalStart instead') - StyledContainerAttributes borderStart({ - Color? color, - double? width, - BorderStyle? style, - }) { - return StyledContainerAttributes( - border: BorderDirectionalDto.only( - start: _borderSide( - color: color, - width: width, - style: style, - ), - ), - ); - } - - @Deprecated('Use paddingDirectionalStart instead') - StyledContainerAttributes paddingStart(double value) { - return StyledContainerAttributes( - padding: EdgeInsetsDirectionalDto.only( - start: value, - ), - ); - } - - @Deprecated('Use paddingDirectionalEnd instead') - StyledContainerAttributes paddingEnd(double value) { - return StyledContainerAttributes( - padding: EdgeInsetsDirectionalDto.only( - end: value, - ), - ); - } - - @Deprecated('Use marginDirectionalStart instead') - StyledContainerAttributes marginStart(double value) { - return StyledContainerAttributes( - margin: EdgeInsetsDirectionalDto.only(start: value), - ); - } - - @Deprecated('Use marginDirectionalStart instead') - StyledContainerAttributes marginEnd(double value) { - return StyledContainerAttributes( - margin: EdgeInsetsDirectionalDto.only(end: value), - ); - } -} diff --git a/lib/src/widgets/container/container.widget.dart b/lib/src/widgets/container/container.widget.dart deleted file mode 100644 index 7e6568cfb..000000000 --- a/lib/src/widgets/container/container.widget.dart +++ /dev/null @@ -1,105 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../../attributes/shared/shared.descriptor.dart'; -import '../../decorators/widget_decorator_wrapper.dart'; -import '../../factory/mix_provider_data.dart'; -import '../empty/empty.widget.dart'; -import '../mix_context_builder.dart'; -import '../styled.widget.dart'; -import 'container.descriptor.dart'; - -typedef Box = StyledContainer; - -class StyledContainer extends StyledWidget { - const StyledContainer({ - @Deprecated('Use the style parameter instead') super.mix, - super.style, - super.key, - super.variants, - super.inherit, - this.child, - }); - - final Widget? child; - - @override - Widget build(BuildContext context) { - return MixBuilder( - style: style, - variants: variants, - builder: (mix) { - return MixedContainer( - mix: mix, - child: child, - ); - }, - ); - } -} - -@Deprecated('Use MixedContainer now') -typedef BoxMixedWidget = MixedContainer; - -class MixedContainer extends StatelessWidget { - // Child Widget - final Widget? child; - - const MixedContainer({ - required this.mix, - this.child, - Key? key, - }) : super(key: key); - - final MixData mix; - - @override - Widget build(BuildContext context) { - final common = CommonDescriptor.fromContext(mix); - final box = StyledContainerDescriptor.fromContext(mix); - - if (!common.visible) { - return const Empty(); - } - var current = child; - - if (common.animated) { - current = AnimatedContainer( - color: box.color, - decoration: box.decoration, - alignment: box.alignment, - constraints: box.constraints, - margin: box.margin, - padding: box.padding, - height: box.height, - width: box.width, - duration: common.animationDuration, - curve: common.animationCurve, - transform: box.transform, - child: current, - ); - } else { - current = Container( - color: box.color, - decoration: box.decoration, - alignment: box.alignment, - constraints: box.constraints, - margin: box.margin, - padding: box.padding, - height: box.height, - width: box.width, - transform: box.transform, - child: current, - ); - } - - if (mix.decorators != null) { - // Wrap parent decorators - current = WidgetDecoratorWrapper( - mix, - child: current, - ); - } - - return current; - } -} diff --git a/lib/src/widgets/container_widget.dart b/lib/src/widgets/container_widget.dart new file mode 100644 index 000000000..17f5bcd5e --- /dev/null +++ b/lib/src/widgets/container_widget.dart @@ -0,0 +1,68 @@ +// ignore_for_file: avoid-unnecessary-reassignment + +import 'package:flutter/material.dart'; + +import '../specs/container_spec.dart'; +import 'styled_widget.dart'; + +typedef Box = StyledContainer; + +class StyledContainer extends StyledWidget { + const StyledContainer({super.style, super.key, super.inherit, this.child}); + + final Widget? child; + + @override + Widget build(BuildContext context) { + return buildWithStyle(context, (data) { + final spec = ContainerSpec.resolve(data); + + return Container( + alignment: spec.alignment, + padding: spec.padding, + decoration: spec.decoration, + constraints: spec.constraints, + margin: spec.margin, + transform: spec.transform, + clipBehavior: spec.clipBehavior ?? Clip.none, + child: child, + ); + }); + } +} + +// class AnimatedStyledContainer extends AnimatedStyledWidget { +// const AnimatedStyledContainer({ +// super.style, +// super.key, +// super.inherit, +// this.child, +// this.mix, +// }); + +// @override +// @Deprecated('Use the style parameter instead') +// final StyleMix? mix; +// final Widget? child; + +// @override +// Widget build(BuildContext context) { +// return buildWithStyle(context, (data) { +// final spec = ContainerSpec.resolve(data); + +// return AnimatedContainer( +// alignment: spec.alignment, +// padding: spec.padding, +// decoration: spec.decoration, +// width: spec.width, +// height: spec.height, +// constraints: spec.constraints, +// margin: spec.margin, +// transform: spec.transform, +// curve: curve, +// duration: duration, +// child: child, +// ); +// }); +// } +// } diff --git a/lib/src/widgets/empty/empty.widget.dart b/lib/src/widgets/empty_widget.dart similarity index 100% rename from lib/src/widgets/empty/empty.widget.dart rename to lib/src/widgets/empty_widget.dart diff --git a/lib/src/widgets/exports.dart b/lib/src/widgets/exports.dart deleted file mode 100644 index d9bf956d7..000000000 --- a/lib/src/widgets/exports.dart +++ /dev/null @@ -1,25 +0,0 @@ -export 'container/container.attributes.dart'; -export 'container/container.descriptor.dart'; -export 'container/container.utilities.dart'; -export 'container/container.widget.dart'; -export 'flex/flex.attributes.dart'; -export 'flex/flex.descriptor.dart'; -export 'flex/flex.utilities.dart'; -export 'flex/flex.widget.dart'; -export 'icon/icon.attributes.dart'; -export 'icon/icon.descriptor.dart'; -export 'icon/icon.utilities.dart'; -export 'icon/icon.widget.dart'; -export 'image/image.attributes.dart'; -export 'image/image.descriptor.dart'; -export 'image/image.utilities.dart'; -export 'mix_context_builder.dart'; -export 'pressable/pressable.widget.dart'; -export 'stack/stack.attributes.dart'; -export 'stack/stack.utilities.dart'; -export 'stack/stack.widget.dart'; -export 'styled.widget.dart'; -export 'text/text.attributes.dart'; -export 'text/text.descriptor.dart'; -export 'text/text.utilities.dart'; -export 'text/text.widget.dart'; diff --git a/lib/src/widgets/flex/flex.attributes.dart b/lib/src/widgets/flex/flex.attributes.dart deleted file mode 100644 index ce3363011..000000000 --- a/lib/src/widgets/flex/flex.attributes.dart +++ /dev/null @@ -1,67 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../../attributes/attribute.dart'; - -@Deprecated('Use FlexStyleAttributes instead') -typedef FlexAttributes = StyledFlexAttributes; - -class StyledFlexAttributes extends StyledWidgetAttributes { - final Axis? direction; - final MainAxisAlignment? mainAxisAlignment; - final CrossAxisAlignment? crossAxisAlignment; - final MainAxisSize? mainAxisSize; - final VerticalDirection? verticalDirection; - final double? gapSize; - - const StyledFlexAttributes({ - this.direction, - this.mainAxisAlignment, - this.crossAxisAlignment, - this.mainAxisSize, - this.verticalDirection, - this.gapSize, - }); - - @override - StyledFlexAttributes merge(StyledFlexAttributes? other) { - if (other == null) return this; - - return StyledFlexAttributes( - direction: other.direction ?? direction, - mainAxisAlignment: other.mainAxisAlignment ?? mainAxisAlignment, - crossAxisAlignment: other.crossAxisAlignment ?? crossAxisAlignment, - mainAxisSize: other.mainAxisSize ?? mainAxisSize, - verticalDirection: other.verticalDirection ?? verticalDirection, - gapSize: other.gapSize ?? gapSize, - ); - } - - @override - StyledFlexAttributes copyWith({ - Axis? direction, - MainAxisAlignment? mainAxisAlignment, - CrossAxisAlignment? crossAxisAlignment, - MainAxisSize? mainAxisSize, - VerticalDirection? verticalDirection, - double? gapSize, - }) { - return StyledFlexAttributes( - direction: direction ?? this.direction, - mainAxisAlignment: mainAxisAlignment ?? this.mainAxisAlignment, - crossAxisAlignment: crossAxisAlignment ?? this.crossAxisAlignment, - mainAxisSize: mainAxisSize ?? this.mainAxisSize, - verticalDirection: verticalDirection ?? this.verticalDirection, - gapSize: gapSize ?? this.gapSize, - ); - } - - @override - get props => [ - direction, - mainAxisAlignment, - crossAxisAlignment, - mainAxisSize, - verticalDirection, - gapSize, - ]; -} diff --git a/lib/src/widgets/flex/flex.descriptor.dart b/lib/src/widgets/flex/flex.descriptor.dart deleted file mode 100644 index 9fa191645..000000000 --- a/lib/src/widgets/flex/flex.descriptor.dart +++ /dev/null @@ -1,61 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../../factory/mix_provider_data.dart'; -import 'flex.attributes.dart'; - -class StyledFlexDescriptor { - final Axis? direction; - final MainAxisAlignment mainAxisAlignment; - final CrossAxisAlignment crossAxisAlignment; - final MainAxisSize mainAxisSize; - final VerticalDirection verticalDirection; - final double? gapSize; - - const StyledFlexDescriptor({ - this.direction, - required this.mainAxisAlignment, - required this.crossAxisAlignment, - required this.mainAxisSize, - required this.verticalDirection, - this.gapSize, - }); - - factory StyledFlexDescriptor.fromContext(MixData mix) { - final flexAttributes = mix.attributesOfType(); - - return StyledFlexDescriptor( - direction: flexAttributes?.direction, - mainAxisAlignment: - flexAttributes?.mainAxisAlignment ?? MainAxisAlignment.start, - crossAxisAlignment: - flexAttributes?.crossAxisAlignment ?? CrossAxisAlignment.center, - mainAxisSize: flexAttributes?.mainAxisSize ?? MainAxisSize.max, - verticalDirection: - flexAttributes?.verticalDirection ?? VerticalDirection.down, - gapSize: flexAttributes?.gapSize, - ); - } - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - - return other is StyledFlexDescriptor && - other.direction == direction && - other.mainAxisAlignment == mainAxisAlignment && - other.crossAxisAlignment == crossAxisAlignment && - other.mainAxisSize == mainAxisSize && - other.verticalDirection == verticalDirection && - other.gapSize == gapSize; - } - - @override - int get hashCode { - return direction.hashCode ^ - mainAxisAlignment.hashCode ^ - crossAxisAlignment.hashCode ^ - mainAxisSize.hashCode ^ - verticalDirection.hashCode ^ - gapSize.hashCode; - } -} diff --git a/lib/src/widgets/flex/flex.utilities.dart b/lib/src/widgets/flex/flex.utilities.dart deleted file mode 100644 index 3dc6f92b2..000000000 --- a/lib/src/widgets/flex/flex.utilities.dart +++ /dev/null @@ -1,67 +0,0 @@ -import 'package:flutter/material.dart'; - -import 'flex.attributes.dart'; - -/// The FlexUtility class is responsible for creating FlexAttributes objects -/// with various directional and sizing information. This allows widgets -/// to be organized in a more intuitive and easier way. -class FlexUtilities { - const FlexUtilities(); - - // Create a FlexAttribues for the direction axis - StyledFlexAttributes direction(Axis direction) { - return StyledFlexAttributes( - direction: direction, - ); - } - - // Create a FlexAttribues for the direction vertical axis - StyledFlexAttributes verticalDirection(VerticalDirection verticalDirection) { - return StyledFlexAttributes( - verticalDirection: verticalDirection, - ); - } - - // Create a FlexAttribues for the main axis - StyledFlexAttributes mainAxisAlignment(MainAxisAlignment mainAxisAlignment) { - return StyledFlexAttributes( - mainAxisAlignment: mainAxisAlignment, - ); - } - - // Create a FlexAttribues for the main axis size - StyledFlexAttributes mainAxisSize(MainAxisSize mainAxisSize) { - return StyledFlexAttributes( - mainAxisSize: mainAxisSize, - ); - } - - // Create a FlexAttribues for the cross axis - @Deprecated('Use crossAxisAlignment instead') - StyledFlexAttributes crossAxis(CrossAxisAlignment crossAxisAlignment) { - return StyledFlexAttributes( - crossAxisAlignment: crossAxisAlignment, - ); - } - - // Create a FlexAttribues for the cross axis - StyledFlexAttributes crossAxisAlignment( - CrossAxisAlignment crossAxisAlignment, - ) { - return StyledFlexAttributes( - crossAxisAlignment: crossAxisAlignment, - ); - } - - // Create a FlexAttribues for gap size - StyledFlexAttributes gap(double gapSize) { - return StyledFlexAttributes( - gapSize: gapSize, - ); - } - - @Deprecated('Use mainAxisAlignment instead') - StyledFlexAttributes mainAxis(MainAxisAlignment mainAxis) { - return mainAxisAlignment(mainAxis); - } -} diff --git a/lib/src/widgets/flex/flex.widget.dart b/lib/src/widgets/flex/flex.widget.dart deleted file mode 100644 index e72b483f6..000000000 --- a/lib/src/widgets/flex/flex.widget.dart +++ /dev/null @@ -1,170 +0,0 @@ -import 'package:flutter/widgets.dart'; - -import '../../factory/mix_provider_data.dart'; -import '../container/container.widget.dart'; -import '../gap/gap_widget.dart'; -import '../mix_context_builder.dart'; -import '../styled.widget.dart'; -import 'flex.descriptor.dart'; - -class StyledFlex extends StyledWidget { - const StyledFlex({ - super.style, - super.key, - super.variants, - super.inherit, - required this.direction, - required this.children, - }); - - final List children; - final Axis direction; - - @override - Widget build(BuildContext context) { - return MixBuilder( - style: style, - variants: variants, - builder: (mix) { - return MixedFlex( - mix: mix, - direction: direction, - children: children, - ); - }, - ); - } -} - -class FlexBox extends StyledWidget { - const FlexBox({ - @Deprecated('Use the style parameter instead') super.mix, - super.style, - super.key, - super.variants, - super.inherit, - required this.direction, - required this.children, - }); - - final List children; - final Axis direction; - - @override - Widget build(BuildContext context) { - return MixBuilder( - style: style, - variants: variants, - builder: (mix) { - return MixedContainer( - mix: mix, - child: MixedFlex( - mix: mix, - direction: direction, - children: children, - ), - ); - }, - ); - } -} - -class StyledRow extends StyledFlex { - const StyledRow({ - super.style, - super.key, - super.variants, - super.inherit, - super.children = const [], - }) : super( - direction: Axis.horizontal, - ); -} - -class StyledColumn extends StyledFlex { - const StyledColumn({ - super.style, - super.key, - super.variants, - super.inherit, - super.children = const [], - }) : super( - direction: Axis.vertical, - ); -} - -class HBox extends FlexBox { - const HBox({ - @Deprecated('Use the style parameter instead') super.mix, - super.style, - super.variants, - super.key, - super.inherit, - super.children = const [], - }) : super( - direction: Axis.horizontal, - ); -} - -class VBox extends FlexBox { - const VBox({ - @Deprecated('Use the style parameter instead') super.mix, - super.style, - super.variants, - super.key, - super.inherit, - super.children = const [], - }) : super( - direction: Axis.vertical, - ); -} - -class MixedFlex extends StatelessWidget { - const MixedFlex({ - super.key, - this.mix, - required this.direction, - required this.children, - }); - - final List children; - final Axis direction; - final MixData? mix; - - // Creates gap to space in between - List _renderChildrenWithGap(double? gapSize, List children) { - // If no gap is set return widgets - if (gapSize == null) return children; - - // List of widgets with gap - final widgets = []; - for (var idx = 0; idx < children.length; idx++) { - final widget = children[idx]; - widgets.add(widget); - // Add gap if not last item if its not last element - - if (idx != children.length - 1) { - widgets.add(Gap(gapSize)); - } - } - - return widgets; - } - - @override - Widget build(BuildContext context) { - final flex = StyledFlexDescriptor.fromContext(mix!); - - return Flex( - direction: direction, - mainAxisAlignment: flex.mainAxisAlignment, - crossAxisAlignment: flex.crossAxisAlignment, - mainAxisSize: flex.mainAxisSize, - verticalDirection: flex.verticalDirection, - children: _renderChildrenWithGap( - flex.gapSize, - children, - ), - ); - } -} diff --git a/lib/src/widgets/flex_widget.dart b/lib/src/widgets/flex_widget.dart new file mode 100644 index 000000000..866878607 --- /dev/null +++ b/lib/src/widgets/flex_widget.dart @@ -0,0 +1,111 @@ +import 'package:flutter/widgets.dart'; + +import '../specs/flex_spec.dart'; +import 'container_widget.dart'; +import 'styled_widget.dart'; + +class StyledFlex extends StyledWidget { + const StyledFlex({ + super.style, + super.key, + super.inherit, + required this.direction, + this.children = const [], + }); + + final List children; + final Axis direction; + + @override + Widget build(BuildContext context) { + return buildWithStyle(context, (data) { + final spec = FlexSpec.resolve(data); + List _childrenWithGap() { + final spacedChildren = []; + for (int i = 0; i < children.length; i++) { + spacedChildren.add(children[i]); + if (i < children.length - 1) { + // spacedChildren.add(Gap(gap)); + } + } + + return spacedChildren; + } + + final fallback = Flex(direction: direction); + + return Flex( + direction: direction, + mainAxisAlignment: spec.mainAxisAlignment ?? fallback.mainAxisAlignment, + mainAxisSize: spec.mainAxisSize ?? fallback.mainAxisSize, + crossAxisAlignment: + spec.crossAxisAlignment ?? fallback.crossAxisAlignment, + verticalDirection: spec.verticalDirection ?? fallback.verticalDirection, + children: _childrenWithGap(), + ); + }); + } +} + +class StyledRow extends StyledFlex { + const StyledRow({ + super.style, + super.key, + super.inherit, + required super.children, + }) : super(direction: Axis.horizontal); +} + +class StyledColumn extends StyledFlex { + const StyledColumn({ + super.style, + super.key, + super.inherit, + super.children, + }) : super(direction: Axis.vertical); +} + +class FlexBox extends StyledWidget { + const FlexBox({ + super.style, + super.key, + super.inherit, + required this.direction, + required this.children, + }); + + final List children; + final Axis direction; + + @override + Widget build(BuildContext context) { + return buildWithStyle(context, (data) { + return StyledContainer( + inherit: true, + child: StyledFlex( + inherit: true, + direction: direction, + children: children, + ), + ); + }); + } +} + +class HBox extends FlexBox { + const HBox({ + super.style, + super.key, + super.inherit, + super.children = const [], + }) : super(direction: Axis.horizontal); +} + +class VBox extends FlexBox { + const VBox({ + super.style, + super.key, + super.inherit, + super.children = const [], + }) : super(direction: Axis.vertical); +} diff --git a/lib/src/widgets/gap/gap_rendering.dart b/lib/src/widgets/gap/gap_rendering.dart deleted file mode 100644 index 3356be485..000000000 --- a/lib/src/widgets/gap/gap_rendering.dart +++ /dev/null @@ -1,143 +0,0 @@ -import 'package:flutter/rendering.dart'; - -class RenderGap extends RenderBox { - RenderGap({ - required double mainAxisExtent, - double? crossAxisExtent, - Axis? fallbackDirection, - Color? color, - }) : _mainAxisExtent = mainAxisExtent, - _crossAxisExtent = crossAxisExtent, - _color = color, - _fallbackDirection = fallbackDirection; - - double get mainAxisExtent => _mainAxisExtent; - double _mainAxisExtent; - set mainAxisExtent(double value) { - if (_mainAxisExtent != value) { - _mainAxisExtent = value; - markNeedsLayout(); - } - } - - double? get crossAxisExtent => _crossAxisExtent; - double? _crossAxisExtent; - set crossAxisExtent(double? value) { - if (_crossAxisExtent != value) { - _crossAxisExtent = value; - markNeedsLayout(); - } - } - - Axis? get fallbackDirection => _fallbackDirection; - Axis? _fallbackDirection; - set fallbackDirection(Axis? value) { - if (_fallbackDirection != value) { - _fallbackDirection = value; - markNeedsLayout(); - } - } - - Axis? get _direction { - final parentNode = parent; - if (parentNode is RenderFlex) { - return parentNode.direction; - } else { - return fallbackDirection; - } - } - - Color? get color => _color; - Color? _color; - set color(Color? value) { - if (_color != value) { - _color = value; - markNeedsPaint(); - } - } - - @override - double computeMinIntrinsicWidth(double height) { - return _computeIntrinsicExtent( - Axis.horizontal, - () => super.computeMinIntrinsicWidth(height), - )!; - } - - @override - double computeMaxIntrinsicWidth(double height) { - return _computeIntrinsicExtent( - Axis.horizontal, - () => super.computeMaxIntrinsicWidth(height), - )!; - } - - @override - double computeMinIntrinsicHeight(double width) { - return _computeIntrinsicExtent( - Axis.vertical, - () => super.computeMinIntrinsicHeight(width), - )!; - } - - @override - double computeMaxIntrinsicHeight(double width) { - return _computeIntrinsicExtent( - Axis.vertical, - () => super.computeMaxIntrinsicHeight(width), - )!; - } - - double? _computeIntrinsicExtent(Axis axis, double Function() compute) { - final Axis? direction = _direction; - if (direction == axis) { - return _mainAxisExtent; - } else { - if (_crossAxisExtent!.isFinite) { - return _crossAxisExtent; - } else { - return compute(); - } - } - } - - @override - Size computeDryLayout(BoxConstraints constraints) { - final Axis? direction = _direction; - - if (direction != null) { - if (direction == Axis.horizontal) { - return constraints.constrain(Size(mainAxisExtent, crossAxisExtent!)); - } else { - return constraints.constrain(Size(crossAxisExtent!, mainAxisExtent)); - } - } else { - throw FlutterError( - 'A Gap widget must be placed directly inside a Flex widget ' - 'or its fallbackDirection must not be null', - ); - } - } - - @override - void performLayout() { - size = computeDryLayout(constraints); - } - - @override - void paint(PaintingContext context, Offset offset) { - if (color != null) { - final Paint paint = Paint()..color = color!; - context.canvas.drawRect(offset & size, paint); - } - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties.add(DoubleProperty('mainAxisExtent', mainAxisExtent)); - properties.add(DoubleProperty('crossAxisExtent', crossAxisExtent)); - properties.add(ColorProperty('color', color)); - properties.add(EnumProperty('fallbackDirection', fallbackDirection)); - } -} diff --git a/lib/src/widgets/gap/gap_widget.dart b/lib/src/widgets/gap/gap_widget.dart deleted file mode 100644 index 329a89629..000000000 --- a/lib/src/widgets/gap/gap_widget.dart +++ /dev/null @@ -1,219 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; - -import 'gap_rendering.dart'; - -// Attribution: -// This code is adapted from the 'gap:2.0.1' package available at: https://pub.dev/packages/gap -// All credit goes to the package author, @letsar (https://github.com/letsar), for developing this fantastic package. -// In order to reduce the number of dependencies, this code was directly incorporated into our project instead of importing the entire package. - -/// A widget that takes a fixed amount of space in the direction of its parent. -/// -/// It only works in the following cases: -/// - It is a descendant of a [Row], [Column], or [Flex], -/// and the path from the [Gap] widget to its enclosing [Row], [Column], or -/// [Flex] must contain only [StatelessWidget]s or [StatefulWidget]s (not other -/// kinds of widgets, like [RenderObjectWidget]s). -/// - It is a descendant of a [Scrollable]. -/// -/// See also: -/// -/// * [MaxGap], a gap that can take, at most, the amount of space specified. -/// * [SliverGap], the sliver version of this widget. -class Gap extends StatelessWidget { - /// Creates a widget that takes a fixed [mainAxisExtent] of space in the - /// direction of its parent. - /// - /// The [mainAxisExtent] must not be null and must be positive. - /// The [crossAxisExtent] must be either null or positive. - const Gap( - this.mainAxisExtent, { - Key? key, - this.crossAxisExtent, - this.color, - }) : assert(mainAxisExtent >= 0 && mainAxisExtent < double.infinity), - assert(crossAxisExtent == null || crossAxisExtent >= 0), - super(key: key); - - /// Creates a widget that takes a fixed [mainAxisExtent] of space in the - /// direction of its parent and expands in the cross axis direction. - /// - /// The [mainAxisExtent] must not be null and must be positive. - const Gap.expand( - double mainAxisExtent, { - Key? key, - Color? color, - }) : this( - mainAxisExtent, - key: key, - crossAxisExtent: double.infinity, - color: color, - ); - - /// The amount of space this widget takes in the direction of its parent. - /// - /// For example: - /// - If the parent is a [Column] this is the height of this widget. - /// - If the parent is a [Row] this is the width of this widget. - /// - /// Must not be null and must be positive. - final double mainAxisExtent; - - /// The amount of space this widget takes in the opposite direction of the - /// parent. - /// - /// For example: - /// - If the parent is a [Column] this is the width of this widget. - /// - If the parent is a [Row] this is the height of this widget. - /// - /// Must be positive or null. If it's null (the default) the cross axis extent - /// will be the same as the constraints of the parent in the opposite - /// direction. - final double? crossAxisExtent; - - /// The color used to fill the gap. - final Color? color; - - @override - Widget build(BuildContext context) { - final scrollableState = Scrollable.maybeOf(context); - final AxisDirection? axisDirection = scrollableState?.axisDirection; - final Axis? fallbackDirection = - axisDirection == null ? null : axisDirectionToAxis(axisDirection); - - return _RawGap( - mainAxisExtent, - crossAxisExtent: crossAxisExtent, - color: color, - fallbackDirection: fallbackDirection, - ); - } -} - -/// A widget that takes, at most, an amount of space in a [Row], [Column], -/// or [Flex] widget. -/// -/// A [MaxGap] widget must be a descendant of a [Row], [Column], or [Flex], -/// and the path from the [MaxGap] widget to its enclosing [Row], [Column], or -/// [Flex] must contain only [StatelessWidget]s or [StatefulWidget]s (not other -/// kinds of widgets, like [RenderObjectWidget]s). -/// -/// See also: -/// -/// * [Gap], the unflexible version of this widget. -class MaxGap extends StatelessWidget { - /// Creates a widget that takes, at most, the specified [mainAxisExtent] of - /// space in a [Row], [Column], or [Flex] widget. - /// - /// The [mainAxisExtent] must not be null and must be positive. - /// The [crossAxisExtent] must be either null or positive. - const MaxGap( - this.mainAxisExtent, { - Key? key, - this.crossAxisExtent, - this.color, - }) : super(key: key); - - /// Creates a widget that takes, at most, the specified [mainAxisExtent] of - /// space in a [Row], [Column], or [Flex] widget and expands in the cross axis - /// direction. - /// - /// The [mainAxisExtent] must not be null and must be positive. - /// The [crossAxisExtent] must be either null or positive. - const MaxGap.expand( - double mainAxisExtent, { - Key? key, - Color? color, - }) : this( - mainAxisExtent, - key: key, - crossAxisExtent: double.infinity, - color: color, - ); - - /// The amount of space this widget takes in the direction of the parent. - /// - /// If the parent is a [Column] this is the height of this widget. - /// If the parent is a [Row] this is the width of this widget. - /// - /// Must not be null and must be positive. - final double mainAxisExtent; - - /// The amount of space this widget takes in the opposite direction of the - /// parent. - /// - /// If the parent is a [Column] this is the width of this widget. - /// If the parent is a [Row] this is the height of this widget. - /// - /// Must be positive or null. If it's null (the default) the cross axis extent - /// will be the same as the constraints of the parent in the opposite - /// direction. - final double? crossAxisExtent; - - /// The color used to fill the gap. - final Color? color; - - @override - Widget build(BuildContext context) { - return Flexible( - child: _RawGap( - mainAxisExtent, - crossAxisExtent: crossAxisExtent, - color: color, - ), - ); - } -} - -class _RawGap extends LeafRenderObjectWidget { - const _RawGap( - this.mainAxisExtent, { - Key? key, - this.crossAxisExtent, - this.color, - this.fallbackDirection, - }) : assert(mainAxisExtent >= 0 && mainAxisExtent < double.infinity), - assert(crossAxisExtent == null || crossAxisExtent >= 0), - super(key: key); - - final double mainAxisExtent; - - final double? crossAxisExtent; - - final Color? color; - - final Axis? fallbackDirection; - - @override - RenderObject createRenderObject(BuildContext context) { - return RenderGap( - mainAxisExtent: mainAxisExtent, - crossAxisExtent: crossAxisExtent ?? 0, - color: color, - fallbackDirection: fallbackDirection, - ); - } - - @override - void updateRenderObject(BuildContext context, RenderGap renderObject) { - renderObject - ..mainAxisExtent = mainAxisExtent - ..crossAxisExtent = crossAxisExtent ?? 0 - ..color = color - ..fallbackDirection = fallbackDirection; - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties.add(DoubleProperty('mainAxisExtent', mainAxisExtent)); - properties.add(DoubleProperty( - 'crossAxisExtent', - crossAxisExtent, - defaultValue: 0, - )); - properties.add(ColorProperty('color', color)); - properties.add(EnumProperty('fallbackDirection', fallbackDirection)); - } -} diff --git a/lib/src/widgets/icon/icon.attributes.dart b/lib/src/widgets/icon/icon.attributes.dart deleted file mode 100644 index 89338ebe4..000000000 --- a/lib/src/widgets/icon/icon.attributes.dart +++ /dev/null @@ -1,41 +0,0 @@ -import '../../attributes/attribute.dart'; -import '../../dtos/color.dto.dart'; - -@Deprecated('Use IconStyleAttributes instead') -typedef IconAttributes = StyledIconAttributes; - -class StyledIconAttributes extends StyledWidgetAttributes { - final ColorDto? color; - final double? size; - const StyledIconAttributes({ - this.color, - this.size, - }); - - @override - StyledIconAttributes copyWith({ - ColorDto? color, - double? size, - }) { - return StyledIconAttributes( - color: color ?? this.color, - size: size ?? this.size, - ); - } - - @override - StyledIconAttributes merge(StyledIconAttributes? other) { - if (other == null) return this; - - return copyWith( - color: other.color, - size: other.size, - ); - } - - @override - get props => [ - color, - size, - ]; -} diff --git a/lib/src/widgets/icon/icon.descriptor.dart b/lib/src/widgets/icon/icon.descriptor.dart deleted file mode 100644 index 1220900a7..000000000 --- a/lib/src/widgets/icon/icon.descriptor.dart +++ /dev/null @@ -1,47 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../../factory/mix_provider_data.dart'; -import 'icon.attributes.dart'; - -class StyledIconDescriptor { - final Color? color; - final double size; - - const StyledIconDescriptor({ - this.color, - required this.size, - }); - - factory StyledIconDescriptor.fromContext(MixData mix) { - final iconAttributes = mix.attributesOfType(); - - StyledIconDescriptor props; - - if (iconAttributes == null) { - props = const StyledIconDescriptor( - size: 24, - ); - } else { - final theme = IconTheme.of(mix.resolveToken.context); - - props = StyledIconDescriptor( - color: iconAttributes.color?.resolve(mix) ?? theme.color, - size: iconAttributes.size ?? theme.size ?? 24, - ); - } - - return props; - } - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - - return other is StyledIconDescriptor && - other.color == color && - other.size == size; - } - - @override - int get hashCode => color.hashCode ^ size.hashCode; -} diff --git a/lib/src/widgets/icon/icon.utilities.dart b/lib/src/widgets/icon/icon.utilities.dart deleted file mode 100644 index 3aa639d45..000000000 --- a/lib/src/widgets/icon/icon.utilities.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../../dtos/color.dto.dart'; -import 'icon.attributes.dart'; - -class IconUtility { - const IconUtility._(); - - static StyledIconAttributes icon({double? size, Color? color}) { - return StyledIconAttributes( - size: size, - color: color != null ? ColorDto(color) : null, - ); - } - - static StyledIconAttributes iconSize(double size) { - return StyledIconAttributes( - size: size, - ); - } - - static StyledIconAttributes iconColor(Color color) { - return StyledIconAttributes( - color: ColorDto(color), - ); - } -} diff --git a/lib/src/widgets/icon/icon.widget.dart b/lib/src/widgets/icon/icon.widget.dart deleted file mode 100644 index 4c02331ef..000000000 --- a/lib/src/widgets/icon/icon.widget.dart +++ /dev/null @@ -1,107 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../../attributes/shared/shared.descriptor.dart'; -import '../../factory/mix_provider_data.dart'; -import '../empty/empty.widget.dart'; -import '../mix_context_builder.dart'; -import '../styled.widget.dart'; -import 'icon.descriptor.dart'; - -@Deprecated('Use StyledIcon now') -typedef IconMix = StyledIcon; - -class StyledIcon extends StyledWidget { - const StyledIcon( - this.icon, { - this.semanticLabel, - @Deprecated('Use the style parameter instead') super.mix, - super.style, - super.key, - super.inherit, - super.variants, - }); - - final IconData? icon; - final String? semanticLabel; - - @override - Widget build(BuildContext context) { - return MixBuilder( - style: style, - variants: variants, - builder: (mix) { - return MixedIcon( - mix: mix, - icon: icon, - ); - }, - ); - } -} - -@Deprecated('Use MixedIcon now') -typedef IconMixedWidget = MixedIcon; - -class MixedIcon extends StatelessWidget { - const MixedIcon({ - required this.mix, - this.icon, - this.semanticLabel, - super.key, - }); - - final IconData? icon; - final MixData mix; - - final String? semanticLabel; - - @override - Widget build(BuildContext context) { - final commonProps = CommonDescriptor.fromContext(mix); - final iconProps = StyledIconDescriptor.fromContext(mix); - - if (!commonProps.visible) { - return const Empty(); - } - Widget iconWidget = Icon( - icon, - color: iconProps.color, - size: iconProps.size, - textDirection: commonProps.textDirection, - ); - - if (commonProps.animated) { - iconWidget = TweenAnimationBuilder( - duration: commonProps.animationDuration, - curve: commonProps.animationCurve, - tween: Tween( - end: iconProps.size, - ), - builder: (context, value, child) { - final sizeValue = value; - - return TweenAnimationBuilder( - duration: commonProps.animationDuration, - curve: commonProps.animationCurve, - tween: ColorTween(end: iconProps.color), - child: child, - builder: (context, value, child) { - final colorValue = value; - - return Icon( - icon, - color: colorValue, - size: sizeValue, - ); - }, - ); - }, - ); - } - - return Semantics( - label: semanticLabel, - child: iconWidget, - ); - } -} diff --git a/lib/src/widgets/icon_widget.dart b/lib/src/widgets/icon_widget.dart new file mode 100644 index 000000000..b942bc766 --- /dev/null +++ b/lib/src/widgets/icon_widget.dart @@ -0,0 +1,65 @@ +import 'package:flutter/material.dart'; + +import '../specs/icon_spec.dart'; +import 'styled_widget.dart'; + +class StyledIcon extends StyledWidget { + const StyledIcon( + this.icon, { + this.semanticLabel, + super.style, + super.key, + super.inherit, + }); + + final IconData? icon; + final String? semanticLabel; + + @override + Widget build(BuildContext context) { + return buildWithStyle(context, (data) { + // Resolve style attributes + final spec = IconSpec.resolve(data); + + return Icon( + icon, + size: spec.size, + color: spec.color, + semanticLabel: semanticLabel, + textDirection: spec.textDirection, + ); + }); + } +} + +class AnimatedStyledIcon extends StyledWidget { + const AnimatedStyledIcon( + this.icon, { + this.semanticLabel, + super.style, + super.key, + required this.progress, + super.inherit, + }); + + final AnimatedIconData icon; + final String? semanticLabel; + final Animation progress; + + @override + Widget build(BuildContext context) { + return buildWithStyle(context, (data) { + // Resolve style attributes + final spec = IconSpec.resolve(data); + + return AnimatedIcon( + icon: icon, + progress: progress, + color: spec.color, + size: spec.size, + semanticLabel: semanticLabel, + textDirection: spec.textDirection, + ); + }); + } +} diff --git a/lib/src/widgets/image/image.attributes.dart b/lib/src/widgets/image/image.attributes.dart deleted file mode 100644 index 17e194e55..000000000 --- a/lib/src/widgets/image/image.attributes.dart +++ /dev/null @@ -1,82 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../../attributes/attribute.dart'; -import '../../dtos/color.dto.dart'; - -@Deprecated('Use StyledImageAttributes instead') -typedef ImageAttributes = StyledImageAttributes; - -class StyledImageAttributes extends StyledWidgetAttributes { - final ColorDto? color; - final double? scale; - - final double? width; - final double? height; - - final BlendMode? colorBlendMode; - final BoxFit? fit; - final AlignmentGeometry? alignment; - final ImageRepeat? repeat; - - const StyledImageAttributes({ - this.color, - this.scale, - this.width, - this.height, - this.colorBlendMode, - this.fit, - this.alignment, - this.repeat, - }); - - @override - StyledImageAttributes copyWith({ - ColorDto? color, - double? scale, - double? width, - double? height, - BlendMode? colorBlendMode, - BoxFit? fit, - AlignmentGeometry? alignment, - ImageRepeat? repeat, - }) { - return StyledImageAttributes( - color: color ?? this.color, - scale: scale ?? this.scale, - width: width ?? this.width, - height: height ?? this.height, - colorBlendMode: colorBlendMode ?? this.colorBlendMode, - fit: fit ?? this.fit, - alignment: alignment ?? this.alignment, - repeat: repeat ?? this.repeat, - ); - } - - @override - StyledImageAttributes merge(StyledImageAttributes? other) { - if (other == null) return this; - - return copyWith( - color: other.color, - scale: other.scale, - width: other.width, - height: other.height, - colorBlendMode: other.colorBlendMode, - fit: other.fit, - alignment: other.alignment, - repeat: other.repeat, - ); - } - - @override - get props => [ - color, - scale, - width, - height, - colorBlendMode, - fit, - alignment, - repeat, - ]; -} diff --git a/lib/src/widgets/image/image.descriptor.dart b/lib/src/widgets/image/image.descriptor.dart deleted file mode 100644 index 14d4080a0..000000000 --- a/lib/src/widgets/image/image.descriptor.dart +++ /dev/null @@ -1,76 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../../factory/mix_provider_data.dart'; -import 'image.attributes.dart'; - -class StyledImageDescriptor { - final Color? color; - final double? scale; - - final double? width; - final double? height; - - final BlendMode? colorBlendMode; - final BoxFit? fit; - - final AlignmentGeometry alignment; - final ImageRepeat repeat; - - const StyledImageDescriptor({ - this.color, - this.scale, - this.width, - this.height, - this.colorBlendMode, - this.fit, - required this.alignment, - required this.repeat, - }); - - factory StyledImageDescriptor.fromContext(MixData mix) { - final attributes = mix.attributesOfType(); - - return StyledImageDescriptor( - color: attributes?.color?.resolve(mix), - scale: attributes?.scale, - width: attributes?.width, - height: attributes?.height, - colorBlendMode: attributes?.colorBlendMode, - fit: attributes?.fit, - alignment: attributes?.alignment ?? Alignment.center, - repeat: attributes?.repeat ?? ImageRepeat.noRepeat, - ); - } - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - - return other is StyledImageDescriptor && - other.color == color && - other.scale == scale && - other.width == width && - other.height == height && - other.colorBlendMode == colorBlendMode && - other.fit == fit && - other.alignment == alignment && - other.repeat == repeat; - } - - @override - int get hashCode { - return color.hashCode ^ - scale.hashCode ^ - width.hashCode ^ - height.hashCode ^ - colorBlendMode.hashCode ^ - fit.hashCode ^ - alignment.hashCode ^ - repeat.hashCode; - } - - @override - String toString() { - return 'ImageMixer(color: $color, scale: $scale, width: $width, height: $height, colorBlendMode: $colorBlendMode, fit: $fit, alignment: $alignment, repeat: $repeat)'; - } -} diff --git a/lib/src/widgets/image/image.utilities.dart b/lib/src/widgets/image/image.utilities.dart deleted file mode 100644 index 5d65cae8d..000000000 --- a/lib/src/widgets/image/image.utilities.dart +++ /dev/null @@ -1,60 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../../dtos/color.dto.dart'; -import 'image.attributes.dart'; - -class ImageUtility { - const ImageUtility._(); - - // ignore: long-parameter-list - static StyledImageAttributes image({ - Color? color, - double? width, - double? height, - double? scale, - BlendMode? colorBlendMode, - BoxFit? fit, - AlignmentGeometry? alignment, - ImageRepeat? repeat, - }) { - return StyledImageAttributes( - color: ColorDto.maybeFrom(color), - scale: scale, - fit: fit, - alignment: alignment, - repeat: repeat, - ); - } - - static StyledImageAttributes color(Color color) { - return StyledImageAttributes(color: ColorDto.from(color)); - } - - static StyledImageAttributes scale(double scale) { - return StyledImageAttributes(scale: scale); - } - - static StyledImageAttributes width(double width) { - return StyledImageAttributes(width: width); - } - - static StyledImageAttributes height(double height) { - return StyledImageAttributes(height: height); - } - - static StyledImageAttributes colorBlendMode(BlendMode colorBlendMode) { - return StyledImageAttributes(colorBlendMode: colorBlendMode); - } - - static StyledImageAttributes fit(BoxFit fit) { - return StyledImageAttributes(fit: fit); - } - - static StyledImageAttributes alignment(AlignmentGeometry alignment) { - return StyledImageAttributes(alignment: alignment); - } - - static StyledImageAttributes repeat(ImageRepeat repeat) { - return StyledImageAttributes(repeat: repeat); - } -} diff --git a/lib/src/widgets/mix_context_builder.dart b/lib/src/widgets/mix_context_builder.dart deleted file mode 100644 index 27a6c90d5..000000000 --- a/lib/src/widgets/mix_context_builder.dart +++ /dev/null @@ -1,32 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../../mix.dart'; -import '../factory/mix_provider.dart'; - -typedef WidgetMixBuilder = Widget Function( - MixData mix, -); - -class MixBuilder extends StyledWidget { - const MixBuilder({ - @Deprecated('Use the style parameter instead') super.mix, - super.style, - super.variants, - super.key, - required WidgetMixBuilder builder, - }) : _builder = builder; - - final WidgetMixBuilder _builder; - - @override - Widget build(BuildContext context) { - final mix = createMixData(context); - - return MixProvider( - mix, - child: Builder( - builder: (context) => _builder(mix), - ), - ); - } -} diff --git a/lib/src/widgets/pressable/pressable.notifier.dart b/lib/src/widgets/pressable/pressable.notifier.dart index 78731e826..525639131 100644 --- a/lib/src/widgets/pressable/pressable.notifier.dart +++ b/lib/src/widgets/pressable/pressable.notifier.dart @@ -4,20 +4,20 @@ import 'pressable_state.dart'; class PressableNotifier extends InheritedWidget { const PressableNotifier({ - Key? key, - required Widget child, + super.key, + required super.child, required this.state, this.focus = false, - }) : super(key: key, child: child); - - final PressableState state; - - final bool focus; + }); static PressableNotifier? of(BuildContext context) { return context.dependOnInheritedWidgetOfExactType(); } + final PressableState state; + + final bool focus; + @override bool updateShouldNotify(PressableNotifier oldWidget) { return oldWidget.focus != focus || oldWidget.state != state; diff --git a/lib/src/widgets/pressable/pressable.widget.dart b/lib/src/widgets/pressable/pressable_widget.dart similarity index 65% rename from lib/src/widgets/pressable/pressable.widget.dart rename to lib/src/widgets/pressable/pressable_widget.dart index 756cf7575..d5a43da90 100644 --- a/lib/src/widgets/pressable/pressable.widget.dart +++ b/lib/src/widgets/pressable/pressable_widget.dart @@ -5,14 +5,14 @@ import 'pressable_state.dart'; class Pressable extends StatefulWidget { const Pressable({ - required this.child, - required this.onPressed, - this.onLongPress, - this.focusNode, this.autofocus = false, - this.onFocusChange, this.behavior, + required this.child, + this.focusNode, super.key, + this.onFocusChange, + this.onLongPress, + required this.onPressed, }); final Widget child; @@ -20,42 +20,43 @@ class Pressable extends StatefulWidget { final VoidCallback? onLongPress; final FocusNode? focusNode; final bool autofocus; - final Function(bool)? onFocusChange; + final Function(bool focus)? onFocusChange; final HitTestBehavior? behavior; @override + // Ignore no need to make this api public. // ignore: library_private_types_in_public_api - _PressableState createState() => _PressableState(); + _PressableWidgetState createState() => _PressableWidgetState(); } -class _PressableState extends State { - late FocusNode node; +class _PressableWidgetState extends State { + late FocusNode _node; @override void initState() { super.initState(); - node = widget.focusNode ?? _createFocusNode(); + _node = widget.focusNode ?? _createFocusNode(); + } + + FocusNode _createFocusNode() { + return FocusNode(debugLabel: '${widget.runtimeType}'); } @override void didUpdateWidget(Pressable oldWidget) { super.didUpdateWidget(oldWidget); if (widget.focusNode != oldWidget.focusNode) { - node = widget.focusNode ?? node; + _node = widget.focusNode ?? _node; } } @override void dispose() { - if (widget.focusNode == null) node.dispose(); + if (widget.focusNode == null) _node.dispose(); super.dispose(); } - FocusNode _createFocusNode() { - return FocusNode(debugLabel: '${widget.runtimeType}'); - } - bool _hover = false; bool _focus = false; bool _pressed = false; @@ -63,7 +64,7 @@ class _PressableState extends State { bool get _onEnabled => widget.onPressed != null || widget.onLongPress != null; - PressableState get state { + PressableState get _state { if (widget.onPressed == null && widget.onLongPress == null) { return PressableState.disabled; } @@ -81,6 +82,7 @@ class _PressableState extends State { return PressableState.hover; } + // ignore: prefer-returning-conditional-expressions return PressableState.inactive; } @@ -100,47 +102,29 @@ class _PressableState extends State { Widget build(BuildContext context) { return MergeSemantics( child: Semantics( - button: true, enabled: _onEnabled, - focusable: _onEnabled && node.canRequestFocus, - focused: node.hasFocus, + button: true, + focusable: _onEnabled && _node.canRequestFocus, + focused: _node.hasFocus, child: GestureDetector( - behavior: widget.behavior, - onTap: () { - widget.onPressed?.call(); - }, - onTapDown: (_) { - updateState(() => _pressed = true); - }, - onTapUp: (_) { - handleUnpress(); - }, - onTapCancel: () { - handleUnpress(); - }, + onTapDown: (_) => updateState(() => _pressed = true), + onTapUp: (_) => handleUnpress(), + onTap: () => widget.onPressed?.call(), + onTapCancel: () => handleUnpress(), + onLongPressCancel: () => updateState(() => _longpressed = false), onLongPress: widget.onLongPress, - onLongPressStart: (_) { - updateState(() => _longpressed = true); - }, - onLongPressEnd: (_) { - updateState(() => _longpressed = false); - }, - onLongPressCancel: () { - updateState(() => _longpressed = false); - }, + onLongPressStart: (_) => updateState(() => _longpressed = true), + onLongPressEnd: (_) => updateState(() => _longpressed = false), + behavior: widget.behavior, child: FocusableActionDetector( - focusNode: node, - autofocus: widget.autofocus, enabled: _onEnabled, + focusNode: _node, + autofocus: widget.autofocus, + onShowFocusHighlight: (v) => updateState(() => _focus = v), + onShowHoverHighlight: (v) => updateState(() => _hover = v), onFocusChange: widget.onFocusChange, - onShowFocusHighlight: (v) { - updateState(() => _focus = v); - }, - onShowHoverHighlight: (v) { - updateState(() => _hover = v); - }, child: PressableNotifier( - state: state, + state: _state, focus: _focus, child: widget.child, ), diff --git a/lib/src/widgets/stack/stack.attributes.dart b/lib/src/widgets/stack/stack.attributes.dart deleted file mode 100644 index 916be0bf7..000000000 --- a/lib/src/widgets/stack/stack.attributes.dart +++ /dev/null @@ -1,49 +0,0 @@ -import 'package:flutter/widgets.dart'; - -import '../../attributes/attribute.dart'; - -@Deprecated('Use StyledStackAttributes instead') -typedef ZBoxAttributes = StyledStackAttributes; - -class StyledStackAttributes extends StyledWidgetAttributes { - final AlignmentGeometry? alignment; - final StackFit? fit; - final Clip? clipBehavior; - - const StyledStackAttributes({ - this.alignment, - this.fit, - this.clipBehavior, - }); - - @override - StyledStackAttributes copyWith({ - AlignmentGeometry? alignment, - StackFit? fit, - Clip? clipBehavior, - }) { - return StyledStackAttributes( - alignment: alignment ?? this.alignment, - fit: fit ?? this.fit, - clipBehavior: clipBehavior ?? this.clipBehavior, - ); - } - - @override - StyledStackAttributes merge(StyledStackAttributes? other) { - if (other == null) return this; - - return copyWith( - alignment: other.alignment, - clipBehavior: other.clipBehavior, - fit: other.fit, - ); - } - - @override - get props => [ - alignment, - fit, - clipBehavior, - ]; -} diff --git a/lib/src/widgets/stack/stack.descriptor.dart b/lib/src/widgets/stack/stack.descriptor.dart deleted file mode 100644 index 5c58b97fb..000000000 --- a/lib/src/widgets/stack/stack.descriptor.dart +++ /dev/null @@ -1,51 +0,0 @@ -import 'package:flutter/widgets.dart'; - -import '../../factory/mix_provider_data.dart'; -import 'stack.attributes.dart'; - -class StyledStackDescriptor { - final AlignmentGeometry alignment; - final StackFit fit; - final Clip clipBehavior; - - const StyledStackDescriptor({ - required this.alignment, - required this.fit, - required this.clipBehavior, - }); - - factory StyledStackDescriptor.fromContext(MixData mix) { - final zBoxAttributes = mix.attributesOfType(); - - return StyledStackDescriptor( - alignment: zBoxAttributes?.alignment ?? Alignment.topLeft, - clipBehavior: zBoxAttributes?.clipBehavior ?? Clip.none, - fit: zBoxAttributes?.fit ?? StackFit.loose, - ); - } - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - - return other is StyledStackDescriptor && - other.alignment == alignment && - other.fit == fit && - other.clipBehavior == clipBehavior; - } - - @override - int get hashCode => alignment.hashCode ^ fit.hashCode ^ clipBehavior.hashCode; - - StyledStackDescriptor copyWith({ - AlignmentGeometry? alignment, - StackFit? fit, - Clip? clipBehavior, - }) { - return StyledStackDescriptor( - alignment: alignment ?? this.alignment, - fit: fit ?? this.fit, - clipBehavior: clipBehavior ?? this.clipBehavior, - ); - } -} diff --git a/lib/src/widgets/stack/stack.utilities.dart b/lib/src/widgets/stack/stack.utilities.dart deleted file mode 100644 index 8e2bd6262..000000000 --- a/lib/src/widgets/stack/stack.utilities.dart +++ /dev/null @@ -1,19 +0,0 @@ -import 'package:flutter/widgets.dart'; - -import 'stack.attributes.dart'; - -class ZBoxUtility { - const ZBoxUtility._(); - - static StyledStackAttributes alignment(AlignmentGeometry alignment) { - return StyledStackAttributes(alignment: alignment); - } - - static StyledStackAttributes fit(StackFit fit) { - return StyledStackAttributes(fit: fit); - } - - static StyledStackAttributes clipBehavior(Clip clip) { - return StyledStackAttributes(clipBehavior: clip); - } -} diff --git a/lib/src/widgets/stack/stack.widget.dart b/lib/src/widgets/stack/stack.widget.dart deleted file mode 100644 index 4d915d577..000000000 --- a/lib/src/widgets/stack/stack.widget.dart +++ /dev/null @@ -1,95 +0,0 @@ -import 'package:flutter/widgets.dart'; - -import '../../factory/mix_provider_data.dart'; -import '../container/container.widget.dart'; -import '../mix_context_builder.dart'; -import '../styled.widget.dart'; -import 'stack.descriptor.dart'; - -// ZBox widget, a custom Box widget that has a Stack as a child. It combines -// the features of a Box widget with a Stack widget, allowing developers to -// create complex and responsive layouts. - -class StyledStack extends StyledWidget { - const StyledStack({ - @Deprecated('Use the style parameter instead') super.mix, - super.style, - super.key, - super.variants, - super.inherit, - this.children = const [], - }); - - final List children; - - @override - Widget build(BuildContext context) { - return MixBuilder( - style: style, - variants: variants, - builder: (mix) { - final zProps = StyledStackDescriptor.fromContext(mix); - - return Stack( - alignment: zProps.alignment, - clipBehavior: zProps.clipBehavior, - fit: zProps.fit, - children: children, - ); - }, - ); - } -} - -class ZBox extends StyledWidget { - const ZBox({ - @Deprecated('Use the style parameter instead') super.mix, - super.style, - super.key, - super.variants, - super.inherit, - this.children = const [], - }); - - final List children; - - @override - Widget build(BuildContext context) { - return MixBuilder( - style: style, - variants: variants, - builder: (mix) { - return MixedContainer( - mix: mix, - child: MixedStack( - mix: mix, - children: children, - ), - ); - }, - ); - } -} - -class MixedStack extends StatelessWidget { - const MixedStack({ - super.key, - required this.mix, - this.children = const [], - }); - - final MixData mix; - final List children; - - @override - Widget build(BuildContext context) { - final zProps = StyledStackDescriptor.fromContext(mix); - - return Stack( - alignment: zProps.alignment, - clipBehavior: zProps.clipBehavior, - fit: zProps.fit, - children: children, - ); - } -} diff --git a/lib/src/widgets/stack_widget.dart b/lib/src/widgets/stack_widget.dart new file mode 100644 index 000000000..0a2121cc3 --- /dev/null +++ b/lib/src/widgets/stack_widget.dart @@ -0,0 +1,54 @@ +import 'package:flutter/widgets.dart'; + +import '../specs/stack_spec.dart'; +import 'container_widget.dart'; +import 'styled_widget.dart'; + +class StyledStack extends StyledWidget { + const StyledStack({ + this.children = const [], + super.inherit, + super.key, + super.style, + }); + + final List children; + + @override + Widget build(BuildContext context) { + return buildWithStyle(context, (data) { + final spec = StackSpec.resolve(data); + + const fallback = Stack(); + + return Stack( + alignment: spec.alignment ?? fallback.alignment, + textDirection: spec.textDirection, + fit: spec.fit ?? fallback.fit, + clipBehavior: spec.clipBehavior ?? fallback.clipBehavior, + children: children, + ); + }); + } +} + +class ZBox extends StyledWidget { + const ZBox({ + this.children = const [], + super.inherit, + super.key, + super.style, + }); + + final List children; + + @override + Widget build(BuildContext context) { + return buildWithStyle(context, (data) { + return StyledContainer( + inherit: true, + child: StyledStack(inherit: true, children: children), + ); + }); + } +} diff --git a/lib/src/widgets/styled.widget.dart b/lib/src/widgets/styled.widget.dart deleted file mode 100644 index a9a0548ff..000000000 --- a/lib/src/widgets/styled.widget.dart +++ /dev/null @@ -1,95 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; - -import '../factory/mix_provider.dart'; -import '../factory/mix_provider_data.dart'; -import '../factory/style_mix.dart'; -import '../variants/variant.dart'; - -@Deprecated('Use MixWidget instead') -typedef MixWidget = StyledWidget; - -abstract class StyledWidget extends StatelessWidget { - /// Constructor - const StyledWidget({ - @Deprecated('Use the style parameter instead') StyleMix? mix, - StyleMix? style, - super.key, - - /// Inherit beavhior is off by default and allows to inherit the style from the parent Context. - /// Only WidgetAttributes are inherited. Decorators will not be inherited as - /// decorators should have already been applied to the parent Widget. - bool inherit = false, - List? variants, - }) : _mix = mix, - _style = style, - _variants = variants, - _inherit = inherit; - - final StyleMix? _mix; - final StyleMix? _style; - final List? _variants; - final bool _inherit; - - StyleMix get style { - if (_style != null && _mix != null) { - throw Exception( - 'Please, give only one of the following parameters style OR mix', - ); - } - - if (_style == null && _mix == null) { - throw Exception( - 'Parameter "style" is required, and will be required in the future.', - ); - } - - return _style ?? _mix ?? StyleMix.constant; - } - - List? get variants => _variants; - - MixData createMixData(BuildContext context) { - final currentMix = MixData.create( - context: context, - style: style.selectVariants(_variants ?? []), - ); - - if (_inherit) { - final parentMix = MixProvider.of(context); - if (parentMix != null) { - return currentMix.inheritFrom(parentMix); - } - } - - return currentMix; - } - - @override - Widget build(BuildContext context); - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - - properties.add( - DiagnosticsProperty('mix', _mix, defaultValue: null), - ); - - properties.add( - DiagnosticsProperty('style', _style, defaultValue: null), - ); - - properties.add( - DiagnosticsProperty('inherit', _inherit, defaultValue: null), - ); - - properties.add( - DiagnosticsProperty>( - 'variants', - variants, - defaultValue: null, - ), - ); - } -} diff --git a/lib/src/widgets/styled_widget.dart b/lib/src/widgets/styled_widget.dart new file mode 100644 index 000000000..89c069a0a --- /dev/null +++ b/lib/src/widgets/styled_widget.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; + +import '../factory/mix_provider.dart'; +import '../factory/style_mix.dart'; + +abstract class StyledWidget extends StatelessWidget { + /// Constructor. + const StyledWidget({ + this.style = StyleMix.empty, + super.key, + + /// Inherit beavhior is off by default and allows to inherit the style from the parent Context. + /// Only WidgetAttributes are inherited. Decorators will not be inherited as + /// decorators should have already been applied to the parent Widget. + this.inherit = false, + }); + + final StyleMix style; + + final bool inherit; + + Widget buildWithStyle(BuildContext context, MixBuilder builder) { + return Mix.build( + context, + style: style, + builder: builder, + inherit: inherit, + ); + } + + @override + Widget build(BuildContext context); +} + +abstract class AnimatedStyledWidget extends StyledWidget { + const AnimatedStyledWidget({ + super.key, + super.inherit, + super.style, + required this.curve, + required this.duration, + }); + + final Curve curve; + final Duration duration; +} diff --git a/lib/src/widgets/text/text.attributes.dart b/lib/src/widgets/text/text.attributes.dart deleted file mode 100644 index e4506620e..000000000 --- a/lib/src/widgets/text/text.attributes.dart +++ /dev/null @@ -1,143 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../../attributes/attribute.dart'; -import '../../dtos/text_style.dto.dart'; -import '../../extensions/helper_ext.dart'; -import 'text_directives/text_directives.dart'; - -@Deprecated('Use TextStyleAttributes instead') -typedef TextAttributes = StyledTextAttributes; - -class StyledTextAttributes extends StyledWidgetAttributes { - final List? _styles; - final TextStyleDto? _style; - - final StrutStyle? strutStyle; - final TextAlign? textAlign; - - final Locale? locale; - final bool? softWrap; - final TextOverflow? overflow; - final double? textScaleFactor; - final int? maxLines; - - final TextWidthBasis? textWidthBasis; - final TextHeightBehavior? textHeightBehavior; - - final List directives; - - const StyledTextAttributes({ - TextStyleDto? style, - List? styles, - this.strutStyle, - this.textAlign, - this.locale, - this.softWrap, - this.overflow, - this.textScaleFactor, - this.maxLines, - this.textWidthBasis, - this.textHeightBehavior, - this.directives = const [], - }) : _styles = styles, - _style = style; - - factory StyledTextAttributes.fromValues({ - TextStyle? style, - StrutStyle? strutStyle, - TextAlign? textAlign, - Locale? locale, - bool? softWrap, - TextOverflow? overflow, - double? textScaleFactor, - int? maxLines, - TextWidthBasis? textWidthBasis, - TextHeightBehavior? textHeightBehavior, - List? directives, - }) { - return StyledTextAttributes( - style: TextStyleDto.maybeFrom(style), - strutStyle: strutStyle, - textAlign: textAlign, - locale: locale, - softWrap: softWrap, - overflow: overflow, - textScaleFactor: textScaleFactor, - maxLines: maxLines, - textWidthBasis: textWidthBasis, - textHeightBehavior: textHeightBehavior, - directives: directives ?? const [], - ); - } - - // Combines the text styles - List? get styles { - return [if (_style != null) _style!, ...?_styles]; - } - - @override - StyledTextAttributes merge(StyledTextAttributes? other) { - if (other == null) return this; - - return copyWith( - // Need to inherit to allow for overrides - styles: other.styles, - - strutStyle: other.strutStyle, - textAlign: other.textAlign, - locale: other.locale, - softWrap: other.softWrap, - overflow: other.overflow, - textScaleFactor: other.textScaleFactor, - maxLines: other.maxLines, - - textWidthBasis: other.textWidthBasis, - textHeightBehavior: other.textHeightBehavior, - directives: other.directives, - ); - } - - @override - StyledTextAttributes copyWith({ - List? styles, - StrutStyle? strutStyle, - TextAlign? textAlign, - Locale? locale, - bool? softWrap, - TextOverflow? overflow, - double? textScaleFactor, - int? maxLines, - TextWidthBasis? textWidthBasis, - TextHeightBehavior? textHeightBehavior, - List? directives, - }) { - return StyledTextAttributes( - styles: [...?this.styles, ...?styles], - strutStyle: this.strutStyle?.merge(strutStyle) ?? strutStyle, - textAlign: textAlign ?? this.textAlign, - locale: locale ?? this.locale, - softWrap: softWrap ?? this.softWrap, - overflow: overflow ?? this.overflow, - textScaleFactor: textScaleFactor ?? this.textScaleFactor, - maxLines: maxLines ?? this.maxLines, - textWidthBasis: textWidthBasis ?? this.textWidthBasis, - textHeightBehavior: textHeightBehavior ?? this.textHeightBehavior, - directives: [...this.directives, ...?directives], - ); - } - - @override - get props => [ - styles, - strutStyle, - textAlign, - locale, - softWrap, - overflow, - textScaleFactor, - maxLines, - textWidthBasis, - textHeightBehavior, - directives, - ]; -} diff --git a/lib/src/widgets/text/text.descriptor.dart b/lib/src/widgets/text/text.descriptor.dart deleted file mode 100644 index 48e3d6245..000000000 --- a/lib/src/widgets/text/text.descriptor.dart +++ /dev/null @@ -1,112 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; - -import '../../dtos/text_style.dto.dart'; -import '../../factory/mix_provider_data.dart'; -import 'text.attributes.dart'; -import 'text_directives/text_directives.dart'; - -class StyledTextDescriptor { - final bool softWrap; - final TextOverflow overflow; - - final TextStyle? style; - final StrutStyle? strutStyle; - final TextAlign? textAlign; - final Locale? locale; - final double? textScaleFactor; - final int? maxLines; - - final TextWidthBasis? textWidthBasis; - final TextHeightBehavior? textHeightBehavior; - final List _directives; - - const StyledTextDescriptor({ - required this.softWrap, - required this.overflow, - this.style, - this.strutStyle, - this.textAlign, - this.locale, - this.textScaleFactor, - this.maxLines, - this.textWidthBasis, - this.textHeightBehavior, - List? directives, - }) : _directives = directives ?? const []; - - factory StyledTextDescriptor.fromContext(MixData mix) { - final textAttributes = mix.attributesOfType(); - - var mergedTextStyleDto = const TextStyleDto(); - - for (var style in textAttributes?.styles ?? []) { - // Convert into a DTO for consistent merge behavior. - final textStyleDto = TextStyleDto.from(style.resolve(mix)); - mergedTextStyleDto = mergedTextStyleDto.merge(textStyleDto); - } - - return StyledTextDescriptor( - // Need to grab colorscheme from context - style: mergedTextStyleDto.resolve(mix), - strutStyle: textAttributes?.strutStyle, - textAlign: textAttributes?.textAlign, - locale: textAttributes?.locale, - softWrap: textAttributes?.softWrap ?? true, - overflow: textAttributes?.overflow ?? TextOverflow.clip, - textScaleFactor: textAttributes?.textScaleFactor, - maxLines: textAttributes?.maxLines, - textWidthBasis: textAttributes?.textWidthBasis, - textHeightBehavior: textAttributes?.textHeightBehavior, - - // Directives - directives: textAttributes?.directives, - ); - } - - String applyTextDirectives( - String? text, - ) { - if (text == null) return ''; - - var modifiedText = text; - for (final directive in _directives) { - modifiedText = directive.modify(modifiedText); - } - - return modifiedText; - } - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - - return other is StyledTextDescriptor && - other.softWrap == softWrap && - other.overflow == overflow && - other.style == style && - other.strutStyle == strutStyle && - other.textAlign == textAlign && - other.locale == locale && - other.textScaleFactor == textScaleFactor && - other.maxLines == maxLines && - other.textWidthBasis == textWidthBasis && - other.textHeightBehavior == textHeightBehavior && - listEquals(other._directives, _directives); - } - - @override - int get hashCode { - return softWrap.hashCode ^ - overflow.hashCode ^ - style.hashCode ^ - strutStyle.hashCode ^ - textAlign.hashCode ^ - locale.hashCode ^ - textScaleFactor.hashCode ^ - maxLines.hashCode ^ - textWidthBasis.hashCode ^ - textHeightBehavior.hashCode ^ - _directives.hashCode; - } -} diff --git a/lib/src/widgets/text/text.utilities.dart b/lib/src/widgets/text/text.utilities.dart deleted file mode 100644 index 50dbf059c..000000000 --- a/lib/src/widgets/text/text.utilities.dart +++ /dev/null @@ -1,129 +0,0 @@ -import 'dart:ui'; - -import 'package:flutter/material.dart'; - -import '../../../mix.dart'; -import '../../dtos/color.dto.dart'; -import '../../dtos/shadow/shadow.dto.dart'; -import '../../dtos/text_style.dto.dart'; -import 'text_directives/text_directives.dart'; - -class TextUtility { - const TextUtility._(); - - // ignore: long-parameter-list - static StyledTextAttributes textStyle({ - String? fontFamily, - FontWeight? fontWeight, - FontStyle? fontStyle, - double? fontSize, - double? letterSpacing, - double? wordSpacing, - TextBaseline? textBaseline, - Color? color, - Color? backgroundColor, - Shadow? shadow, - List? shadows, - List? fontFeatures, - TextDecoration? decoration, - Color? decorationColor, - TextDecorationStyle? decorationStyle, - Paint? foreground, - Paint? background, - String? debugLabel, - Locale? locale, - double? height, - // If asStyle is provided, all other parameters will be ignored. - TextStyle? as, - }) { - if (as != null) { - return StyledTextAttributes(style: TextStyleDto.from(as)); - } - - List? convertShadows() { - List combinedShadows = [...?shadows, if (shadow != null) shadow]; - - final shadowDtos = combinedShadows.map((e) => ShadowDto.from(e)).toList(); - - if (shadowDtos.isEmpty) return null; - - return shadowDtos; - } - - return StyledTextAttributes( - style: TextStyleDto( - fontFamily: fontFamily, - fontWeight: fontWeight, - fontStyle: fontStyle, - fontSize: fontSize, - letterSpacing: letterSpacing, - wordSpacing: wordSpacing, - textBaseline: textBaseline, - color: ColorDto.maybeFrom(color), - backgroundColor: ColorDto.maybeFrom(backgroundColor), - shadows: convertShadows(), - fontFeatures: fontFeatures, - decoration: decoration, - decorationColor: ColorDto.maybeFrom(decorationColor), - decorationStyle: decorationStyle, - debugLabel: debugLabel, - locale: locale, - height: height, - foreground: foreground, - background: background, - ), - ); - } - - static StyledTextAttributes strutStyle(StrutStyle strutStyle) { - return StyledTextAttributes(strutStyle: strutStyle); - } - - static StyledTextAttributes textAlign(TextAlign textAlign) { - return StyledTextAttributes(textAlign: textAlign); - } - - static StyledTextAttributes locale(Locale locale) { - return StyledTextAttributes(locale: locale); - } - - static StyledTextAttributes softWrap(bool softWrap) { - return StyledTextAttributes(softWrap: softWrap); - } - - static StyledTextAttributes overflow(TextOverflow overflow) { - return StyledTextAttributes(overflow: overflow); - } - - static StyledTextAttributes textScaleFactor(double textScaleFactor) { - return StyledTextAttributes(textScaleFactor: textScaleFactor); - } - - static StyledTextAttributes maxLines(int maxLines) { - return StyledTextAttributes(maxLines: maxLines); - } - - static StyledTextAttributes textWidthBasis(TextWidthBasis textWidthBasis) { - return StyledTextAttributes(textWidthBasis: textWidthBasis); - } - - static StyledTextAttributes directives(List directives) { - return StyledTextAttributes(directives: directives); - } - - static StyledTextAttributes directive(TextDirective directive) { - return StyledTextAttributes(directives: [directive]); - } -} - -class TextFriendlyUtility { - const TextFriendlyUtility._(); - - static StyledTextAttributes bold() { - return TextUtility.textStyle(fontWeight: FontWeight.bold); - } - - static StyledTextAttributes italic() { - return TextUtility.textStyle(fontStyle: FontStyle.italic); - } -} diff --git a/lib/src/widgets/text/text.widget.dart b/lib/src/widgets/text/text.widget.dart deleted file mode 100644 index 65016ced8..000000000 --- a/lib/src/widgets/text/text.widget.dart +++ /dev/null @@ -1,124 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; - -import '../../attributes/shared/shared.descriptor.dart'; -import '../../factory/mix_provider_data.dart'; -import '../empty/empty.widget.dart'; -import '../mix_context_builder.dart'; -import '../styled.widget.dart'; -import 'text.descriptor.dart'; - -@Deprecated('Use StyledText now') -typedef TextMix = StyledText; - -class StyledText extends StyledWidget { - const StyledText( - this.text, { - @Deprecated('Use the style parameter instead') super.mix, - super.style, - super.key, - super.variants, - super.inherit, - this.semanticsLabel, - }); - - final String text; - final String? semanticsLabel; - - @override - Widget build(BuildContext context) { - return MixBuilder( - style: style, - builder: (mix) { - return MixedText( - mix: mix, - content: text, - semanticsLabel: semanticsLabel, - ); - }, - ); - } -} - -@Deprecated('Use MixedText now') -typedef TextMixedWidget = MixedText; - -class MixedText extends StatelessWidget { - const MixedText({ - required this.mix, - required this.content, - super.key, - this.semanticsLabel, - }); - - final String content; - final MixData mix; - - final String? semanticsLabel; - - @override - Widget build(BuildContext context) { - final common = CommonDescriptor.fromContext(mix); - final text = StyledTextDescriptor.fromContext(mix); - - if (!common.visible) { - return const Empty(); - } - - final modifiedContent = text.applyTextDirectives(content); - - final textWidget = Text( - modifiedContent, - textDirection: common.textDirection, - textWidthBasis: text.textWidthBasis, - textScaleFactor: text.textScaleFactor, - locale: text.locale, - maxLines: text.maxLines, - overflow: text.overflow, - softWrap: text.softWrap, - strutStyle: text.strutStyle, - style: text.style, - textAlign: text.textAlign, - textHeightBehavior: text.textHeightBehavior, - semanticsLabel: semanticsLabel, - ); - - if (common.animated) { - return AnimatedDefaultTextStyle( - style: text.style ?? - Theme.of(context).textTheme.bodyLarge ?? - const TextStyle(), - duration: common.animationDuration, - curve: common.animationCurve, - softWrap: text.softWrap, - overflow: text.overflow, - textAlign: text.textAlign, - maxLines: text.maxLines, - child: textWidget, - ); - } else { - return textWidget; - } - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - - properties.add( - DiagnosticsProperty( - 'text', - content, - defaultValue: null, - ), - ); - - properties.add( - DiagnosticsProperty( - 'props', - mix, - defaultValue: null, - ), - ); - } -} diff --git a/lib/src/widgets/text/text_directives/text_directive_helpers.dart b/lib/src/widgets/text/text_directives/text_directive_helpers.dart deleted file mode 100644 index 18f8c4c80..000000000 --- a/lib/src/widgets/text/text_directives/text_directive_helpers.dart +++ /dev/null @@ -1,28 +0,0 @@ -String capitalize(String string) { - final current = string; - if (current.isEmpty) { - return string; - } - - return current[0].toUpperCase() + current.substring(1); -} - -String titleCase(String string) { - const separator = ' '; - final current = string; - List words = current.split(separator).map(capitalize).toList(); - - return words.join(separator); -} - -String sentenceCase(String string) { - const separator = ' '; - final current = string; - List words = current.split(separator); - - if (words.isNotEmpty) { - capitalize(words[0]); - } - - return words.join(separator); -} diff --git a/lib/src/widgets/text/text_directives/text_directives.dart b/lib/src/widgets/text/text_directives/text_directives.dart deleted file mode 100644 index 481b305ac..000000000 --- a/lib/src/widgets/text/text_directives/text_directives.dart +++ /dev/null @@ -1,53 +0,0 @@ -import '../../../directives/directive_attribute.dart'; -import 'text_directive_helpers.dart'; - -class UppercaseDirective extends TextDirective { - const UppercaseDirective(); - - @override - String modify(String value) { - return value.toUpperCase(); - } -} - -class CapitalizeDirective extends TextDirective { - const CapitalizeDirective(); - - @override - String modify(String value) { - return capitalize(value); - } -} - -class LowercaseDirective extends TextDirective { - const LowercaseDirective(); - - @override - String modify(String value) { - return value.toLowerCase(); - } -} - -class SentenceCaseDirective extends TextDirective { - const SentenceCaseDirective(); - - @override - String modify(String value) { - return sentenceCase(value); - } -} - -class TitleCaseDirective extends TextDirective { - const TitleCaseDirective(); - @override - String modify(String value) { - return titleCase(value); - } -} - -abstract class TextDirective extends Directive { - const TextDirective(); - - @override - String modify(String value); -} diff --git a/lib/src/widgets/text/text_legacy.utilities.dart b/lib/src/widgets/text/text_legacy.utilities.dart deleted file mode 100644 index 61fe65e74..000000000 --- a/lib/src/widgets/text/text_legacy.utilities.dart +++ /dev/null @@ -1,320 +0,0 @@ -import 'dart:ui'; - -import 'package:flutter/material.dart'; - -import '../../dtos/text_style.dto.dart'; -import 'text.attributes.dart'; -import 'text_directives/text_directives.dart'; - -const kDeprecationMessage = 'Will be removed in the future'; - -@Deprecated('Use TextUtility instead') -class LegacyTextUtility { - const LegacyTextUtility._(); - - @Deprecated(kDeprecationMessage) - static StyledTextAttributes style(TextStyle? style) { - if (style == null) return const StyledTextAttributes(); - - return StyledTextAttributes(style: TextStyleDto.from(style)); - } - - @Deprecated(kDeprecationMessage) - static StyledTextAttributes strutStyle(StrutStyle strutStyle) { - return StyledTextAttributes(strutStyle: strutStyle); - } - - @Deprecated(kDeprecationMessage) - static StyledTextAttributes textAlign(TextAlign textAlign) { - return StyledTextAttributes(textAlign: textAlign); - } - - @Deprecated(kDeprecationMessage) - static StyledTextAttributes locale(Locale locale) { - return StyledTextAttributes(locale: locale); - } - - @Deprecated(kDeprecationMessage) - static StyledTextAttributes softWrap(bool softWrap) { - return StyledTextAttributes(softWrap: softWrap); - } - - @Deprecated(kDeprecationMessage) - static StyledTextAttributes overflow(TextOverflow overflow) { - return StyledTextAttributes(overflow: overflow); - } - - @Deprecated(kDeprecationMessage) - static StyledTextAttributes textScaleFactor(double textScaleFactor) { - return StyledTextAttributes(textScaleFactor: textScaleFactor); - } - - @Deprecated(kDeprecationMessage) - static StyledTextAttributes maxLines(int maxLines) { - return StyledTextAttributes(maxLines: maxLines); - } - - @Deprecated(kDeprecationMessage) - static StyledTextAttributes textWidthBasis(TextWidthBasis textWidthBasis) { - return StyledTextAttributes(textWidthBasis: textWidthBasis); - } - - @Deprecated(kDeprecationMessage) - static StyledTextAttributes directives(List directives) { - return StyledTextAttributes(directives: directives); - } - - @Deprecated(kDeprecationMessage) - static StyledTextAttributes directive(TextDirective directive) { - return StyledTextAttributes(directives: [directive]); - } -} - -@Deprecated(kDeprecationMessage) -class LegacyTextStyleUtility { - const LegacyTextStyleUtility._(); - - @Deprecated(kDeprecationMessage) - static StyledTextAttributes background(Paint? background) { - return LegacyTextUtility.style( - TextStyle(background: background), - ); - } - - @Deprecated(kDeprecationMessage) - static StyledTextAttributes backgroundColor(Color? backgroundColor) { - return LegacyTextUtility.style( - TextStyle(backgroundColor: backgroundColor), - ); - } - - @Deprecated(kDeprecationMessage) - static StyledTextAttributes color(Color? color) { - return LegacyTextUtility.style( - TextStyle(color: color), - ); - } - - @Deprecated(kDeprecationMessage) - static StyledTextAttributes debugLabel(String? debugLabel) { - return LegacyTextUtility.style( - TextStyle(debugLabel: debugLabel), - ); - } - - @Deprecated(kDeprecationMessage) - static StyledTextAttributes decoration(TextDecoration? decoration) { - return LegacyTextUtility.style( - TextStyle(decoration: decoration), - ); - } - - @Deprecated(kDeprecationMessage) - static StyledTextAttributes decorationColor(Color? decorationColor) { - return LegacyTextUtility.style( - TextStyle(decorationColor: decorationColor), - ); - } - - @Deprecated(kDeprecationMessage) - static StyledTextAttributes decorationStyle( - TextDecorationStyle? decorationStyle,) { - return LegacyTextUtility.style( - TextStyle(decorationStyle: decorationStyle), - ); - } - - @Deprecated(kDeprecationMessage) - static StyledTextAttributes decorationThickness(double? decorationThickness) { - return LegacyTextUtility.style( - TextStyle(decorationThickness: decorationThickness), - ); - } - - @Deprecated(kDeprecationMessage) - static StyledTextAttributes fontFamily(String? fontFamily) { - return LegacyTextUtility.style( - TextStyle(fontFamily: fontFamily), - ); - } - - @Deprecated(kDeprecationMessage) - static StyledTextAttributes fontFamilyFallback( - List? fontFamilyFallback,) { - return LegacyTextUtility.style( - TextStyle(fontFamilyFallback: fontFamilyFallback), - ); - } - - @Deprecated(kDeprecationMessage) - static StyledTextAttributes fontFeatures(List? fontFeatures) { - return LegacyTextUtility.style( - TextStyle(fontFeatures: fontFeatures), - ); - } - - @Deprecated(kDeprecationMessage) - static StyledTextAttributes fontSize(double? fontSize) { - return LegacyTextUtility.style( - TextStyle(fontSize: fontSize), - ); - } - - @Deprecated(kDeprecationMessage) - static StyledTextAttributes fontStyle(FontStyle? fontStyle) { - return LegacyTextUtility.style( - TextStyle(fontStyle: fontStyle), - ); - } - - @Deprecated(kDeprecationMessage) - static StyledTextAttributes fontWeight(FontWeight? fontWeight) { - return LegacyTextUtility.style( - TextStyle(fontWeight: fontWeight), - ); - } - - @Deprecated(kDeprecationMessage) - static StyledTextAttributes foreground(Paint? foreground) { - return LegacyTextUtility.style( - TextStyle(foreground: foreground), - ); - } - - @Deprecated(kDeprecationMessage) - static StyledTextAttributes height(double? height) { - return LegacyTextUtility.style( - TextStyle(height: height), - ); - } - - @Deprecated(kDeprecationMessage) - static StyledTextAttributes inherit({inherit = true}) { - return LegacyTextUtility.style( - TextStyle(inherit: inherit), - ); - } - - @Deprecated(kDeprecationMessage) - static StyledTextAttributes letterSpacing(double? letterSpacing) { - return LegacyTextUtility.style( - TextStyle(letterSpacing: letterSpacing), - ); - } - - @Deprecated(kDeprecationMessage) - static StyledTextAttributes locale(Locale? locale) { - return LegacyTextUtility.style( - TextStyle(locale: locale), - ); - } - - @Deprecated(kDeprecationMessage) - static StyledTextAttributes shadows(List shadows) { - return LegacyTextUtility.style( - TextStyle(shadows: shadows), - ); - } - - @Deprecated(kDeprecationMessage) - static StyledTextAttributes textBaseline(TextBaseline? textBaseline) { - return LegacyTextUtility.style( - TextStyle(textBaseline: textBaseline), - ); - } - - @Deprecated(kDeprecationMessage) - static StyledTextAttributes wordSpacing(double? wordSpacing) { - return LegacyTextUtility.style( - TextStyle(wordSpacing: wordSpacing), - ); - } -} - -@Deprecated(kDeprecationMessage) -class LegacyTextFriendlyUtility { - const LegacyTextFriendlyUtility._(); - - @Deprecated(kDeprecationMessage) - // ignore: long-parameter-list - static StyledTextAttributes textStyle({ - Color? color, - Paint? background, - Color? backgroundColor, - String? debugLabel, - FontWeight? weight, - double? size, - String? family, - FontStyle? style, - double? letterSpacing, - double? wordSpacing, - List? fontFamilyFallback, - Paint? foreground, - double? height, - bool inherit = true, - Locale? locale, - Shadow? shadow, - List? shadows, - double? decorationThickness, - TextDecorationStyle? decorationStyle, - TextBaseline? textBaseline, - Color? decorationColor, - }) { - combineShadows() { - final s = shadows ?? []; - if (shadow != null) s.add(shadow); - - return s; - } - - return LegacyTextUtility.style( - TextStyle( - color: color, - fontWeight: weight, - fontSize: size, - fontFamily: family, - fontStyle: style, - letterSpacing: letterSpacing, - wordSpacing: wordSpacing, - fontFamilyFallback: fontFamilyFallback, - foreground: foreground, - height: height, - inherit: inherit, - locale: locale, - shadows: combineShadows(), - textBaseline: textBaseline, - decorationThickness: decorationThickness, - decorationStyle: decorationStyle, - decorationColor: decorationColor, - debugLabel: debugLabel, - background: background, - backgroundColor: backgroundColor, - ), - ); - } - - @Deprecated(kDeprecationMessage) - static StyledTextAttributes bold() { - return LegacyTextStyleUtility.fontWeight(FontWeight.bold); - } - - @Deprecated(kDeprecationMessage) - static StyledTextAttributes italic() { - return LegacyTextStyleUtility.fontStyle(FontStyle.italic); - } - - @Deprecated(kDeprecationMessage) - static StyledTextAttributes textShadow({ - Color color = const Color(0x33000000), - double blurRadius = 0.0, - Offset offset = Offset.zero, - }) { - return LegacyTextStyleUtility.shadows([ - Shadow( - color: color, - blurRadius: blurRadius, - offset: offset, - ), - ]); - } -} diff --git a/lib/src/widgets/text_widget.dart b/lib/src/widgets/text_widget.dart new file mode 100644 index 000000000..971cd6ef1 --- /dev/null +++ b/lib/src/widgets/text_widget.dart @@ -0,0 +1,45 @@ +import 'package:flutter/material.dart'; + +import '../specs/text_spec.dart'; +import 'styled_widget.dart'; + +@Deprecated('Use StyledText now') +typedef TextMix = StyledText; + +class StyledText extends StyledWidget { + const StyledText( + this.text, { + this.semanticsLabel, + super.style, + super.key, + super.inherit, + this.locale, + }); + + final String text; + final String? semanticsLabel; + final Locale? locale; + + @override + Widget build(BuildContext context) { + return buildWithStyle(context, (data) { + final spec = TextSpec.resolve(data); + + return Text( + spec.applyTextDirectives(text), + style: spec.style, + strutStyle: spec.strutStyle, + textAlign: spec.textAlign, + textDirection: spec.textDirection ?? TextDirection.ltr, + locale: locale, + softWrap: spec.softWrap, + overflow: spec.overflow, + textScaleFactor: spec.textScaleFactor, + maxLines: spec.maxLines, + semanticsLabel: semanticsLabel, + textWidthBasis: spec.textWidthBasis, + textHeightBehavior: spec.textHeightBehavior, + ); + }); + } +} diff --git a/pubspec.lock b/pubspec.lock index 6cacd8f91..ac00ca7eb 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,34 +5,18 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: d976d24314f193899a3079b14fe336215a63a3b1e1c3743eabba8f83e049e9a9 + sha256: ae92f5d747aee634b87f89d9946000c2de774be1d6ac3e58268224348cd0101a url: "https://pub.dev" source: hosted - version: "49.0.0" + version: "61.0.0" analyzer: dependency: transitive description: name: analyzer - sha256: "40ba2c6d2ab41a66476f8f1f099da6be0795c1b47221f5e2c5f8ad6048cdffae" + sha256: ea3d8652bda62982addfd92fdc2d0214e5f82e43325104990d4f4c4a2a313562 url: "https://pub.dev" source: hosted - version: "5.1.0" - analyzer_plugin: - dependency: transitive - description: - name: analyzer_plugin - sha256: c1d5f167683de03d5ab6c3b53fc9aeefc5d59476e7810ba7bbddff50c6f4392d - url: "https://pub.dev" - source: hosted - version: "0.11.2" - ansicolor: - dependency: transitive - description: - name: ansicolor - sha256: "607f8fa9786f392043f169898923e6c59b4518242b68b8862eb8a8b7d9c30b4a" - url: "https://pub.dev" - source: hosted - version: "2.0.1" + version: "5.13.0" args: dependency: transitive description: @@ -61,10 +45,10 @@ packages: dependency: transitive description: name: build - sha256: "43865b79fbb78532e4bff7c33087aa43b1d488c4fdef014eaef568af6d8016dc" + sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.1" build_config: dependency: transitive description: @@ -93,10 +77,10 @@ packages: dependency: "direct dev" description: name: build_runner - sha256: "5e1929ad37d48bd382b124266cb8e521de5548d406a45a5ae6656c13dab73e37" + sha256: "10c6bcdbf9d049a0b666702cf1cee4ddfdc38f02a19d35ae392863b47519848b" url: "https://pub.dev" source: hosted - version: "2.4.5" + version: "2.4.6" build_runner_core: dependency: transitive description: @@ -117,10 +101,10 @@ packages: dependency: transitive description: name: built_value - sha256: "598a2a682e2a7a90f08ba39c0aaa9374c5112340f0a2e275f61b59389543d166" + sha256: ff627b645b28fb8bdb69e645f910c2458fd6b65f6585c3a53e0626024897dedf url: "https://pub.dev" source: hosted - version: "8.6.1" + version: "8.6.2" characters: dependency: transitive description: @@ -149,18 +133,18 @@ packages: dependency: transitive description: name: code_builder - sha256: "4ad01d6e56db961d29661561effde45e519939fdaeb46c351275b182eac70189" + sha256: "315a598c7fbe77f22de1c9da7cfd6fd21816312f16ffa124453b4fc679e540f1" url: "https://pub.dev" source: hosted - version: "4.5.0" + version: "4.6.0" collection: dependency: transitive description: name: collection - sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" + sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 url: "https://pub.dev" source: hosted - version: "1.17.1" + version: "1.17.2" convert: dependency: transitive description: @@ -177,22 +161,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.3" - csslib: - dependency: transitive - description: - name: csslib - sha256: "706b5707578e0c1b4b7550f64078f0a0f19dec3f50a178ffae7006b0a9ca58fb" - url: "https://pub.dev" - source: hosted - version: "1.0.0" - dart_code_metrics: + dart_code_metrics_presets: dependency: "direct dev" description: - name: dart_code_metrics - sha256: "219607f5abbf4c0d254ca39ee009f9ff28df91c40aef26718fde15af6b7a6c24" + name: dart_code_metrics_presets + sha256: "47ab5f4e9e224b6f59287f1822d51a6de357bf0cd0593882390107644b091c2e" url: "https://pub.dev" source: hosted - version: "4.21.3" + version: "2.4.0" dart_style: dependency: transitive description: @@ -234,10 +210,10 @@ packages: dependency: "direct dev" description: name: flutter_lints - sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c + sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04 url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.0.3" flutter_test: dependency: "direct dev" description: flutter @@ -267,22 +243,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.1" - html: - dependency: transitive - description: - name: html - sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a" - url: "https://pub.dev" - source: hosted - version: "0.15.4" - http: - dependency: transitive - description: - name: http - sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2" - url: "https://pub.dev" - source: hosted - version: "0.13.6" http_multi_server: dependency: transitive description: @@ -343,20 +303,20 @@ packages: dependency: transitive description: name: matcher - sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" url: "https://pub.dev" source: hosted - version: "0.12.15" + version: "0.12.16" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" url: "https://pub.dev" source: hosted - version: "0.2.0" + version: "0.5.0" meta: - dependency: transitive + dependency: "direct dev" description: name: meta sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" @@ -371,6 +331,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.4" + mockito: + dependency: "direct dev" + description: + name: mockito + sha256: "7d5b53bcd556c1bc7ffbe4e4d5a19c3e112b7e925e9e172dd7c6ad0630812616" + url: "https://pub.dev" + source: hosted + version: "5.4.2" package_config: dependency: transitive description: @@ -380,29 +348,13 @@ packages: source: hosted version: "2.1.0" path: - dependency: transitive + dependency: "direct dev" description: name: path sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" url: "https://pub.dev" source: hosted version: "1.8.3" - petitparser: - dependency: transitive - description: - name: petitparser - sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750 - url: "https://pub.dev" - source: hosted - version: "5.4.0" - platform: - dependency: transitive - description: - name: platform - sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" - url: "https://pub.dev" - source: hosted - version: "3.1.0" pool: dependency: transitive description: @@ -411,14 +363,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.1" - process: - dependency: transitive - description: - name: process - sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" - url: "https://pub.dev" - source: hosted - version: "4.2.4" pub_semver: dependency: transitive description: @@ -427,14 +371,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" - pub_updater: - dependency: transitive - description: - name: pub_updater - sha256: "42890302ab2672adf567dc2b20e55b4ecc29d7e19c63b6b98143ab68dd717d3a" - url: "https://pub.dev" - source: hosted - version: "0.2.4" pubspec_parse: dependency: transitive description: @@ -464,14 +400,22 @@ packages: description: flutter source: sdk version: "0.0.99" + source_gen: + dependency: transitive + description: + name: source_gen + sha256: fc0da689e5302edb6177fdd964efcb7f58912f43c28c2047a808f5bfff643d16 + url: "https://pub.dev" + source: hosted + version: "1.4.0" source_span: dependency: transitive description: name: source_span - sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.10.0" stack_trace: dependency: transitive description: @@ -516,10 +460,10 @@ packages: dependency: transitive description: name: test_api - sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb + sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" url: "https://pub.dev" source: hosted - version: "0.5.1" + version: "0.6.0" test_cov_console: dependency: "direct dev" description: @@ -560,22 +504,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" - web_socket_channel: + web: dependency: transitive description: - name: web_socket_channel - sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b + name: web + sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 url: "https://pub.dev" source: hosted - version: "2.4.0" - xml: + version: "0.1.4-beta" + web_socket_channel: dependency: transitive description: - name: xml - sha256: "5bc72e1e45e941d825fd7468b9b4cc3b9327942649aeb6fc5cdbf135f0a86e84" + name: web_socket_channel + sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b url: "https://pub.dev" source: hosted - version: "6.3.0" + version: "2.4.0" yaml: dependency: transitive description: @@ -585,5 +529,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.0.0 <4.0.0" + dart: ">=3.1.0-185.0.dev <4.0.0" flutter: ">=3.3.0" diff --git a/pubspec.yaml b/pubspec.yaml index 1d80b3da4..5d9bb6d8e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,7 +4,7 @@ version: 0.0.7 homepage: https://github.com/leoafarias/mix environment: - sdk: ">=2.17.0 <3.0.0" + sdk: ">=2.17.0 <4.0.0" flutter: ">=3.3.0" dependencies: @@ -14,7 +14,11 @@ dependencies: dev_dependencies: build_runner: ^2.3.2 test_cov_console: ^0.2.2 - flutter_lints: ^2.0.1 + flutter_lints: ^2.0.3 flutter_test: sdk: flutter - dart_code_metrics: ^4.21.2 + dart_code_metrics_presets: ^2.4.0 + path: ^1.8.3 + mockito: ^5.4.2 + meta: ^1.9.1 + diff --git a/reference.md b/reference.md new file mode 100644 index 000000000..eedff7c88 --- /dev/null +++ b/reference.md @@ -0,0 +1,101 @@ +### `Container` Widget + +1. `alignment`: AlignmentGeometry +2. `padding`: EdgeInsetsGeometry +3. `color`: Color +4. `decoration`: Decoration +5. `foregroundDecoration`: Decoration +6. `width`: double +7. `height`: double +8. `constraints`: BoxConstraints +9. `margin`: EdgeInsetsGeometry +10. `transform`: Matrix4 +11. `transformAlignment`: AlignmentGeometry + +### `Text` Widget + +1. `style`: TextStyle +2. `textAlign`: TextAlign +3. `textDirection`: TextDirection +4. `softWrap`: bool +5. `overflow`: TextOverflow +6. `textScaleFactor`: double +7. `maxLines`: int +8. `semanticsLabel`: String +9. `textWidthBasis`: TextWidthBasis +10. `textHeightBehavior`: TextHeightBehavior + +### `Icon` Widget + +1. `icon`: IconData +2. `size`: double +3. `color`: Color +4. `semanticLabel`: String +5. `textDirection`: TextDirection + +### `Image` Widget + +1. `image`: ImageProvider +2. `width`: double +3. `height`: double +4. `color`: Color +5. `colorBlendMode`: BlendMode +6. `fit`: BoxFit +7. `alignment`: AlignmentGeometry +8. `repeat`: ImageRepeat +9. `centerSlice`: Rect +10. `matchTextDirection`: bool +11. `gaplessPlayback`: bool + +### `Flex` Widget + +1. `direction`: Axis +2. `mainAxisAlignment`: MainAxisAlignment +3. `mainAxisSize`: MainAxisSize +4. `crossAxisAlignment`: CrossAxisAlignment +5. `textDirection`: TextDirection +6. `verticalDirection`: VerticalDirection + +### `Stack` Widget + +1. `alignment`: AlignmentGeometry +2. `textDirection`: TextDirection +3. `fit`: StackFit +4. `clipBehavior`: Clip +5. `children`: List + +### Shared Properties + +1. `alignment`: AlignmentGeometry - Shared by `Container`, `Image`, `Flex`, and `Stack`. +2. `textDirection`: TextDirection - Shared by `Text`, `Icon`, `Flex`, and `Stack`. +3. `color`: Color - Shared by `Container`, `Icon`, and `Image`. + +### `TextStyle` Properties + +1. `background`: Paint? +2. `backgroundColor`: Color? +3. `color`: Color? +4. `debugLabel`: String? +5. `decoration`: TextDecoration? +6. `decorationColor`: Color? +7. `decorationStyle`: TextDecorationStyle? +8. `decorationThickness`: double? +9. `fontFamily`: String? +10. `fontFamilyFallback`: List? +11. `fontFeatures`: List? +12. `fontSize`: double? +13. `fontStyle`: FontStyle? +14. `fontVariations`: List? +15. `fontWeight`: FontWeight? +16. `foreground`: Paint? +17. `hashCode`: int (read-only, inherited) +18. `height`: double? +19. `inherit`: bool +20. `leadingDistribution`: TextLeadingDistribution? +21. `letterSpacing`: double? +22. `locale`: Locale? +23. `overflow`: TextOverflow? +24. `runtimeType`: Type (read-only, inherited) +25. `shadows`: List? +26. `textBaseline`: TextBaseline? +27. `wordSpacing`: double? diff --git a/test/attributes/box_attributes_test.dart b/test/attributes/box_attributes_test.dart deleted file mode 100644 index 25bba62bc..000000000 --- a/test/attributes/box_attributes_test.dart +++ /dev/null @@ -1,391 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:mix/mix.dart'; -import 'package:mix/src/dtos/border/border.dto.dart'; -import 'package:mix/src/dtos/color.dto.dart'; -import 'package:mix/src/dtos/edge_insets/edge_insets.dto.dart'; -import 'package:mix/src/dtos/radius/border_radius.dto.dart'; -import 'package:mix/src/dtos/radius/radius_dto.dart'; -import 'package:mix/src/dtos/shadow/box_shadow.dto.dart'; - -void main() { - group("Box Attributes", () { - test('-> Margin', () async { - const marginAttribute = - StyledContainerAttributes(margin: EdgeInsetsDto.all(20)); - final marginUtilityAttribute = margin(20); - - expect( - marginAttribute, - marginUtilityAttribute, - reason: 'Margin utility does not match attribute', - ); - - expect( - marginAttribute.margin, - marginUtilityAttribute.margin, - reason: 'Margin values on attribute do not match', - ); - - expect( - marginAttribute.margin, - const EdgeInsetsDto.all(20), - reason: 'Margin attribute does not match EdgeInsetsDto.all(20)', - ); - }); - - test('-> Padding', () async { - const paddingAttribute = - StyledContainerAttributes(padding: EdgeInsetsDto.all(30)); - final paddingUtilityAttribute = padding(30); - - expect( - paddingAttribute, - paddingUtilityAttribute, - reason: 'Padding utility does not match attribute', - ); - - expect( - paddingAttribute.padding, - paddingUtilityAttribute.padding, - reason: 'Padding values on attribute do not match', - ); - - expect( - paddingAttribute.padding, - const EdgeInsetsDto.all(30), - reason: 'Padding attribute does not match EdgeInsetsDto.all(30)', - ); - }); - - test('-> Width', () async { - const widthAttribute = StyledContainerAttributes(width: 40); - final widthUtilityAttribute = width(40); - - expect( - widthAttribute, - widthUtilityAttribute, - reason: 'Width utility does not match attribute', - ); - - expect( - widthAttribute.width, - widthUtilityAttribute.width, - reason: 'Width values on attribute do not match', - ); - - expect( - widthAttribute.width, - 40, - reason: 'Width attribute does not match 20', - ); - }); - - test('-> Height', () async { - const heightAttribute = StyledContainerAttributes(height: 50); - final heightUtilityAttribute = height(50); - - expect( - heightAttribute, - heightUtilityAttribute, - reason: 'Height utility does not match attribute', - ); - - expect( - heightAttribute.height, - heightUtilityAttribute.height, - reason: 'Height values on attribute do not match', - ); - - expect( - heightAttribute.height, - 50, - reason: 'Height attribute does not match 20', - ); - }); - - test('-> Min Width', () async { - const minWidthAttribute = StyledContainerAttributes(minWidth: 60); - final minWidthUtilityAttribute = minWidth(60); - - expect( - minWidthAttribute, - minWidthUtilityAttribute, - reason: 'Min Width utility does not match attribute', - ); - - expect( - minWidthAttribute.minWidth, - minWidthUtilityAttribute.minWidth, - reason: 'Min Width values on attribute do not match', - ); - - expect( - minWidthAttribute.minWidth, - 60, - reason: 'Min Width attribute does not match 20', - ); - }); - - test('-> Min Height', () async { - const minHeightAttribute = StyledContainerAttributes(minHeight: 70); - final minHeightUtilityAttribute = minHeight(70); - - expect( - minHeightAttribute, - minHeightUtilityAttribute, - reason: 'Min Height utility does not match attribute', - ); - - expect( - minHeightAttribute.minHeight, - minHeightUtilityAttribute.minHeight, - reason: 'Min Height values on attribute do not match', - ); - - expect( - minHeightAttribute.minHeight, - 70, - reason: 'Min Height attribute does not match 20', - ); - }); - - test('-> Max Width', () async { - const maxWidthAttribute = StyledContainerAttributes(maxWidth: 80); - final maxWidthUtilityAttribute = maxWidth(80); - - expect( - maxWidthAttribute, - maxWidthUtilityAttribute, - reason: 'Max Width utility does not match attribute', - ); - - expect( - maxWidthAttribute.maxWidth, - maxWidthUtilityAttribute.maxWidth, - reason: 'Max Width values on attribute do not match', - ); - - expect( - maxWidthAttribute.maxWidth, - 80, - reason: 'Max Width attribute does not match 20', - ); - }); - - test('-> Max Height', () async { - const maxHeightAttribute = StyledContainerAttributes(maxHeight: 90); - final maxHeightUtilityAttribute = maxHeight(90); - - expect( - maxHeightAttribute, - maxHeightUtilityAttribute, - reason: 'Max Height utility does not match attribute', - ); - - expect( - maxHeightAttribute.maxHeight, - maxHeightUtilityAttribute.maxHeight, - reason: 'Max Height values on attribute do not match', - ); - - expect( - maxHeightAttribute.maxHeight, - 90, - reason: 'Max Height attribute does not match 20', - ); - }); - - test('-> Alignment', () async { - const alignmentAttribute = - StyledContainerAttributes(alignment: Alignment.topLeft); - final alignmentUtilityAttribute = alignment(Alignment.topLeft); - - expect( - alignmentAttribute, - alignmentUtilityAttribute, - reason: 'Alignment utility does not match attribute', - ); - - expect( - alignmentAttribute.alignment, - alignmentUtilityAttribute.alignment, - reason: 'Alignment values on attribute do not match', - ); - - expect( - alignmentAttribute.alignment, - Alignment.topLeft, - reason: 'Alignment attribute does not match Alignment.topLeft', - ); - }); - - // Border Radius - - test('-> Border Radius', () async { - const borderRadiusAttribute = StyledContainerAttributes( - borderRadius: BorderRadiusDto.all( - RadiusDto.circular(10), - ), - ); - final borderRadiusUtilityAttribute = rounded(10); - - expect( - borderRadiusAttribute, - borderRadiusUtilityAttribute, - reason: 'Border Radius utility does not match attribute', - ); - - expect( - borderRadiusAttribute.borderRadius, - borderRadiusUtilityAttribute.borderRadius, - reason: 'Border Radius values on attribute do not match', - ); - - expect( - borderRadiusAttribute.borderRadius, - const BorderRadiusDto.all(RadiusDto.circular(10)), - reason: - 'Border Radius attribute does not match BorderRadiusDto.all(10)', - ); - - const topLeftBorderRadius = StyledContainerAttributes( - borderRadius: BorderRadiusDto.only( - topLeft: RadiusDto.circular(10), - ), - ); - final topLeftBorderRadiusUtility = roundedOnly(topLeft: 10); - - expect( - topLeftBorderRadius, - topLeftBorderRadiusUtility, - reason: 'Border Radius utility does not match attribute', - ); - - expect( - topLeftBorderRadius.borderRadius, - topLeftBorderRadiusUtility.borderRadius, - reason: 'Border Radius values on attribute do not match', - ); - - expect( - topLeftBorderRadius.borderRadius, - const BorderRadiusDto.only(topLeft: RadiusDto.circular(10)), - reason: - 'Border Radius attribute does not match BorderRadiusDto.only(topLeft: 10)', - ); - }); - - // Border - - test('-> Border', () async { - final borderAttribute = StyledContainerAttributes( - border: BorderDto.all( - style: BorderStyle.solid, - width: 10, - color: const ColorDto(Colors.red), - ), - ); - final borderUtilityAttribute = border( - style: BorderStyle.solid, - width: 10, - color: Colors.red, - ); - - expect( - borderAttribute, - borderUtilityAttribute, - reason: 'Border utility does not match attribute', - ); - - expect( - borderAttribute.border, - borderUtilityAttribute.border, - reason: 'Border values on attribute do not match', - ); - - expect( - borderAttribute.border, - BorderDto.all( - style: BorderStyle.solid, - width: 10, - color: const ColorDto(Colors.red), - ), - reason: 'Border attribute does not match BorderDto.all(10)', - ); - }); - - // Shadows - - test('-> Shadow', () async { - const shadowAttribute = StyledContainerAttributes( - boxShadow: [ - BoxShadowDto( - color: ColorDto(Colors.red), - offset: Offset(10, 10), - blurRadius: 10, - spreadRadius: 15, - ), - ], - ); - final shadowUtilityAttribute = shadow( - color: Colors.red, - offset: const Offset(10, 10), - blurRadius: 10, - spreadRadius: 15, - ); - - expect( - shadowAttribute, - shadowUtilityAttribute, - reason: 'Shadow utility does not match attribute', - ); - - expect( - shadowAttribute.boxShadow, - shadowUtilityAttribute.boxShadow, - reason: 'Shadow values on attribute do not match', - ); - - expect( - shadowAttribute.boxShadow, - [ - const BoxShadowDto( - color: ColorDto(Colors.red), - offset: Offset(10, 10), - blurRadius: 10, - spreadRadius: 15, - ), - ], - reason: 'Shadow attribute does not match ShadowDto(10)', - ); - }); - - // Transform - - test('-> Transform', () async { - final transformAttribute = StyledContainerAttributes( - transform: Matrix4.rotationZ(0.1), - ); - final transformUtilityAttribute = transform(Matrix4.rotationZ(0.1)); - - expect( - transformAttribute, - transformUtilityAttribute, - reason: 'Transform utility does not match attribute', - ); - - expect( - transformAttribute.transform, - transformUtilityAttribute.transform, - reason: 'Transform values on attribute do not match', - ); - - expect( - transformAttribute.transform, - Matrix4.rotationZ(0.1), - reason: 'Transform attribute does not match TransformDto(10)', - ); - }); - }); -} diff --git a/test/attributes/inherited_attribute_test.dart b/test/attributes/inherited_attribute_test.dart deleted file mode 100644 index 84199de85..000000000 --- a/test/attributes/inherited_attribute_test.dart +++ /dev/null @@ -1,298 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:mix/mix.dart' hide border, onEnabled, icon, iconColor; - -import '../helpers/testing_utils.dart'; - -const activated = StyleVariant("activated"); - -const customIcon = InheritedIconAttribute.icon; -const withSize = InheritedIconAttribute.withSize; -const withColor = InheritedIconAttribute.withColor; - -const inputDecoration = InputDecorationThemeAttribute.inputDecoration; - -class InheritedIconAttribute extends StyledWidgetAttributes { - const InheritedIconAttribute({ - this.color, - this.size, - }); - - final Color? color; - final double? size; - - @override - InheritedIconAttribute merge(InheritedIconAttribute other) { - return copyWith( - color: other.color, - size: other.size, - ); - } - - @override - InheritedIconAttribute copyWith({ - Color? color, - double? size, - }) { - return InheritedIconAttribute( - color: color ?? this.color, - size: size ?? this.size, - ); - } - - static InheritedIconAttribute icon({ - required Color color, - required double size, - }) { - return InheritedIconAttribute( - size: size, - color: color, - ); - } - - static InheritedIconAttribute withColor(Color color) { - return InheritedIconAttribute( - color: color, - ); - } - - static InheritedIconAttribute withSize(double size) { - return InheritedIconAttribute( - size: size, - ); - } - - @override - get props => [color, size]; -} - -class InputDecorationThemeAttribute extends StyledWidgetAttributes { - final Color? iconColor; - final Color? fillColor; - final InputBorder? border; - const InputDecorationThemeAttribute({ - this.iconColor, - this.fillColor, - this.border, - }); - - @override - InputDecorationThemeAttribute merge(InputDecorationThemeAttribute? other) { - if (other == null) return this; - - return InputDecorationThemeAttribute( - iconColor: other.iconColor, - fillColor: other.fillColor, - border: other.border, - ); - } - - InputDecorationTheme resolve() { - return InputDecorationTheme( - iconColor: iconColor, - fillColor: fillColor, - border: border, - ); - } - - @override - InputDecorationThemeAttribute copyWith({ - Color? iconColor, - Color? fillColor, - InputBorder? border, - }) { - return InputDecorationThemeAttribute( - iconColor: iconColor ?? this.iconColor, - fillColor: fillColor ?? this.fillColor, - border: border ?? this.border, - ); - } - - static InputDecorationThemeAttribute inputDecoration({ - Color? iconColor, - Color? fillColor, - InputBorder? border, - }) { - return InputDecorationThemeAttribute( - iconColor: iconColor, - fillColor: fillColor, - border: border, - ); - } - - @override - get props => [iconColor, fillColor, border]; -} - -final mix = StyleMix( - withSize(23), - withColor(Colors.green), - inputDecoration( - border: const UnderlineInputBorder( - borderSide: BorderSide(color: Colors.red, width: 2), - ), - ), - inputDecoration( - fillColor: Colors.red, - ), - activated(withColor(Colors.blue), inputDecoration(fillColor: Colors.green)), - const SharedStyleAttributes(textDirection: TextDirection.rtl), -); - -class CustomWidget extends StatelessWidget { - const CustomWidget( - this.icon, { - this.semanticLabel, - Key? key, - this.variants = const [], - }) : super( - key: key, - ); - - final IconData? icon; - final String? semanticLabel; - final List variants; - - @override - Widget build(BuildContext context) { - return MixBuilder( - variants: variants, - style: mix, - builder: (mix) { - final attribute = mix.attributesOfType()!; - - final sharedProps = CommonDescriptor.fromContext(mix); - - return Semantics( - label: semanticLabel, - child: Column( - children: [ - Icon( - icon, - color: attribute.color, - size: attribute.size, - textDirection: sharedProps.textDirection, - ), - ], - ), - ); - }, - ); - } -} - -class TextFieldWidget extends StatelessWidget { - const TextFieldWidget( - this.icon, { - this.semanticLabel, - Key? key, - this.variants = const [], - }) : super( - key: key, - ); - - final IconData? icon; - final String? semanticLabel; - final List variants; - - @override - Widget build(BuildContext context) { - return MixBuilder( - style: mix, - variants: variants, - builder: (mix) { - final decorationTheme = - mix.dependOnAttributesOfType(); - - return Semantics( - label: semanticLabel, - child: Column( - children: [ - TextField( - decoration: const InputDecoration() - .applyDefaults(decorationTheme.resolve()), - ), - ], - ), - ); - }, - ); - } -} - -void main() { - group("inherited icon attribute", () { - testWidgets('without variants', (tester) async { - await tester.pumpWidget( - const TestMixWidget( - child: CustomWidget(Icons.bolt), - ), - ); - - final icon = tester.widget(find.byType(Icon)); - - expect(icon.color, Colors.green); - expect(icon.size, 23); - expect(icon.icon, Icons.bolt); - - expect(icon.textDirection, TextDirection.rtl); - }); - - testWidgets('with variant', (tester) async { - await tester.pumpWidget( - const TestMixWidget( - child: CustomWidget( - Icons.bolt, - variants: [activated], - ), - ), - ); - - final icon = tester.widget(find.byType(Icon)); - - expect(icon.color, Colors.blue); - expect(icon.size, 23); - expect(icon.icon, Icons.bolt); - - expect(icon.textDirection, TextDirection.rtl); - }); - }); - - group("inherited input theme attribute", () { - testWidgets('without variants', (tester) async { - await tester.pumpWidget( - const TestMixWidget( - child: MaterialApp( - home: Material( - child: TextFieldWidget( - Icons.bolt, - variants: [], - ), - ), - ), - ), - ); - - final textField = tester.widget(find.byType(TextField)); - expect(textField.decoration!.fillColor, Colors.red); - }); - - testWidgets('with variants', (tester) async { - await tester.pumpWidget( - const TestMixWidget( - child: MaterialApp( - home: Scaffold( - body: TextFieldWidget( - Icons.bolt, - variants: [activated], - ), - ), - ), - ), - ); - - final textField = tester.widget(find.byType(TextField)); - expect(textField.decoration!.fillColor, Colors.green); - }); - }); -} diff --git a/test/attributes/nested_attributes_test.dart b/test/attributes/nested_attributes_test.dart deleted file mode 100644 index a1d772ae5..000000000 --- a/test/attributes/nested_attributes_test.dart +++ /dev/null @@ -1,33 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:mix/mix.dart'; -import 'package:mix/src/dtos/color.dto.dart'; -import 'package:mix/src/dtos/edge_insets/edge_insets.dto.dart'; - -void main() { - group("Nested Attributes", () { - test('-> Apply Mixes', () async { - final styleMargin = StyleMix( - const StyledContainerAttributes( - margin: EdgeInsetsDto.all(20), - ), - ); - final styleColor = StyleMix( - const StyledContainerAttributes(color: ColorDto(Colors.red)), - ); - - final nestedStyleUtility = StyleMix.combine([styleColor, styleMargin]); - - final boxAttributesUtility = nestedStyleUtility.values - .attributesOfType(); - - expect( - boxAttributesUtility, - const StyledContainerAttributes( - color: ColorDto(Colors.red), - margin: EdgeInsetsDto.all(20), - ), - ); - }); - }); -} diff --git a/test/attributes/text_attributes_test.dart b/test/attributes/text_attributes_test.dart deleted file mode 100644 index 7cc8291dd..000000000 --- a/test/attributes/text_attributes_test.dart +++ /dev/null @@ -1,72 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:mix/src/widgets/text/text.attributes.dart'; - -import '../helpers/random_dto.dart'; - -void main() { - group('TextAttributes', () { - test('Test merge method', () { - final ta1 = RandomGenerator.textAttributes(); - - const ta2 = StyledTextAttributes( - textAlign: TextAlign.right, - maxLines: 3, - strutStyle: StrutStyle(forceStrutHeight: true), - ); - - final merged = ta1.merge(ta2); - - expect(merged.textAlign, TextAlign.right); - expect(merged.maxLines, 3); - expect(merged.strutStyle?.forceStrutHeight, true); - }); - - test('Test copyWith method', () { - const ta1 = StyledTextAttributes( - textAlign: TextAlign.left, - maxLines: 2, - ); - - final ta2 = ta1.copyWith( - textAlign: TextAlign.right, - maxLines: 3, - strutStyle: const StrutStyle(forceStrutHeight: true), - ); - - expect(ta2.textAlign, TextAlign.right); - expect(ta2.maxLines, 3); - expect(ta2.strutStyle?.forceStrutHeight, true); - - // Ensure original object properties remain unchanged - expect(ta1.textAlign, TextAlign.left); - expect(ta1.maxLines, 2); - expect(ta1.strutStyle, null); - }); - - test('Test merge method with null values', () { - const ta1 = StyledTextAttributes( - textAlign: TextAlign.left, - maxLines: 2, - ); - - const ta2 = StyledTextAttributes( - textAlign: null, - maxLines: 3, - textScaleFactor: 2, - ); - - var merged = ta1.merge(ta2); - - expect(merged.textAlign, TextAlign.left); - expect(merged.maxLines, 3); - expect(merged.textScaleFactor, 2); - - merged = ta2.merge(ta1); - - expect(merged.textAlign, TextAlign.left); - expect(merged.maxLines, 2); - expect(merged.textScaleFactor, 2); - }); - }); -} diff --git a/test/attributes/utilities_test.dart b/test/attributes/utilities_test.dart deleted file mode 100644 index 94c0be699..000000000 --- a/test/attributes/utilities_test.dart +++ /dev/null @@ -1,104 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:mix/mix.dart'; - -void main() { - group("Test Mix Utilities", () { - test('Test Margin Utilities', () async { - expect( - margin(20), - ContainerStyleUtilities().marginInsets( - const EdgeInsets.only(left: 20, top: 20, right: 20, bottom: 20), - ), - ); - expect( - marginTop(18), - ContainerStyleUtilities().marginInsets( - const EdgeInsets.only(top: 18), - ), - ); - expect( - marginBottom(17), - ContainerStyleUtilities().marginInsets( - const EdgeInsets.only(bottom: 17), - ), - ); - expect( - marginRight(16), - ContainerStyleUtilities().marginInsets( - const EdgeInsets.only(right: 16), - ), - ); - expect( - marginLeft(15), - ContainerStyleUtilities().marginInsets( - const EdgeInsets.only(left: 15), - ), - ); - expect( - marginHorizontal(14), - ContainerStyleUtilities().marginInsets( - const EdgeInsets.only(left: 14, right: 14), - ), - ); - expect( - marginVertical(13), - ContainerStyleUtilities().marginInsets( - const EdgeInsets.only(top: 13, bottom: 13), - ), - ); - }); - - test('Test Padding Utilities', () async { - expect( - padding(20), - ContainerStyleUtilities().paddingInsets( - const EdgeInsets.all(20), - ), - reason: "Padding not applied to all", - ); - expect( - paddingTop(18), - ContainerStyleUtilities().paddingInsets( - const EdgeInsets.only(top: 18), - ), - reason: "Padding not applied to top", - ); - expect( - paddingBottom(17), - ContainerStyleUtilities().paddingInsets( - const EdgeInsets.only(bottom: 17), - ), - reason: "Padding not applied to bottom", - ); - expect( - paddingRight(16), - ContainerStyleUtilities().paddingInsets( - const EdgeInsets.only(right: 16), - ), - reason: "Padding not applied to right", - ); - expect( - paddingLeft(15), - ContainerStyleUtilities().paddingInsets( - const EdgeInsets.only(left: 15), - ), - reason: "Padding not applied to left", - ); - expect( - paddingHorizontal(14), - ContainerStyleUtilities().paddingInsets( - const EdgeInsets.only(left: 14, right: 14), - ), - reason: "Padding not applied to horizontally", - ); - expect( - paddingVertical(13), - ContainerStyleUtilities().paddingInsets( - const EdgeInsets.only(top: 13, bottom: 13), - ), - reason: "Padding not applied to vertically", - ); - }); - }); -} diff --git a/test/dtos/border/border_side_test.dart b/test/dtos/border/border_side_test.dart deleted file mode 100644 index f3feac424..000000000 --- a/test/dtos/border/border_side_test.dart +++ /dev/null @@ -1,100 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:mix/src/dtos/border/border_side.dto.dart'; -import 'package:mix/src/dtos/color.dto.dart'; - -void main() { - group('BorderSideDto', () { - test('fromBorderSide() constructor', () { - BorderSide borderSide = const BorderSide( - color: Colors.red, - width: 2.0, - style: BorderStyle.solid, - // Removed for compatibility - // strokeAlign: 12.0, - ); - - BorderSideDto result = BorderSideDto.from(borderSide); - - expect(result.color?.value, borderSide.color); - expect(result.width, borderSide.width); - expect(result.style, borderSide.style); - expect(result.strokeAlign, borderSide.strokeAlign); - }); - test('copyWith() & merge() method', () { - BorderSide borderSide = const BorderSide( - color: Colors.red, - width: 2.0, - style: BorderStyle.solid, - // Removed for compatibility - // strokeAlign: 12.0, - ); - - BorderSideDto result = BorderSideDto.from(borderSide); - - BorderSideDto copy = result.copyWith( - color: const ColorDto(Colors.blue), - width: 3.0, - strokeAlign: 13.0, - ); - - BorderSideDto merge = result.merge(copy); - - expect(copy.color?.value, Colors.blue); - expect(copy.width, 3.0); - expect(copy.style, BorderStyle.solid); - // Removed for compatibility - // expect(copy.strokeAlign, 13.0); - - expect(copy, merge); - }); - }); - - test( - 'BorderSideDto equality', - () { - const borderSide = BorderSide( - color: Colors.red, - width: 2.0, - style: BorderStyle.solid, - strokeAlign: 12.0, - ); - - final result = BorderSideDto.from(borderSide); - - const same = BorderSideDto.only( - color: ColorDto.from(Colors.red), - width: 2.0, - style: BorderStyle.solid, - strokeAlign: 12.0, - ); - - const different = BorderSideDto.only( - color: ColorDto(Colors.blue), - width: 3.0, - style: BorderStyle.solid, - strokeAlign: 13.0, - ); - - final mergedDifferent = different.merge(same); - - final mergedSame = result.merge(same); - - expect( - result, - mergedSame, - reason: 'merge same objects should return the same object', - ); - expect( - result, - isNot(different), - reason: 'different objects should not be equal', - ); - expect( - mergedDifferent, - isNot(different), - reason: 'merged different objects should not be equal', - ); - }, - ); -} diff --git a/test/dtos/edge_insets/edge_insets_test.dart b/test/dtos/edge_insets/edge_insets_test.dart deleted file mode 100644 index 83985fdf6..000000000 --- a/test/dtos/edge_insets/edge_insets_test.dart +++ /dev/null @@ -1,121 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:mix/mix.dart'; -import 'package:mix/src/dtos/edge_insets/edge_insets.dto.dart'; - -import '../../helpers/context_finder.dart'; - -void main() { - group('EdgeInsetsDto tests', () { - test('EdgeInsetsDto.all creates EdgeInsetsDto with equal values', () { - const edgeInsetsDto = EdgeInsetsDto.all(8.0); - expect(edgeInsetsDto.top, 8.0); - expect(edgeInsetsDto.bottom, 8.0); - expect(edgeInsetsDto.left, 8.0); - expect(edgeInsetsDto.right, 8.0); - }); - - test('from method creates EdgeInsetsDto from EdgeInsets', () { - const edgeInsets = EdgeInsets.only(top: 16.0, left: 8.0); - final edgeInsetsDto = EdgeInsetsDto.from(edgeInsets); - expect(edgeInsetsDto.top, 16.0); - expect(edgeInsetsDto.bottom, null); - expect(edgeInsetsDto.left, 8.0); - expect(edgeInsetsDto.right, null); - }); - - test('copyWith method creates new EdgeInsetsDto with updated values', () { - const edgeInsetsDto = EdgeInsetsDto.only( - top: 4.0, - bottom: 4.0, - left: 4.0, - right: 4.0, - ); - final newEdgeInsetsDto = edgeInsetsDto.copyWith(left: 8.0, right: 8.0); - expect(newEdgeInsetsDto.top, 4.0); - expect(newEdgeInsetsDto.bottom, 4.0); - expect(newEdgeInsetsDto.left, 8.0); - expect(newEdgeInsetsDto.right, 8.0); - }); - - test('merge method merges two EdgeInsetsDto objects', () { - const firstEdgeInsetsDto = EdgeInsetsDto.only( - top: 4.0, - bottom: 4.0, - left: 4.0, - right: 4.0, - ); - const secondEdgeInsetsDto = EdgeInsetsDto.only( - left: 8.0, - right: 8.0, - ); - final mergedEdgeInsetsDto = firstEdgeInsetsDto.merge(secondEdgeInsetsDto); - expect(mergedEdgeInsetsDto.top, 4.0); - expect(mergedEdgeInsetsDto.bottom, 4.0); - expect(mergedEdgeInsetsDto.left, 8.0); - expect(mergedEdgeInsetsDto.right, 8.0); - }); - - testWidgets('Resolve method returns EdgeInsets with resolved values', ( - WidgetTester tester, - ) async { - final edgeInsetsDto = EdgeInsetsDto.only( - top: $space.small, - left: $space.xlarge, - bottom: 4.0, - right: 4.0, - ); - - final overrideEdgeInsets = EdgeInsetsDto.only( - bottom: $space.medium, - right: $space.xxlarge, - left: 20, - ); - - final mixTheme = MixThemeData(); - await tester.pumpWidget(MaterialApp( - home: Builder(builder: (context) { - return MixTheme( - data: mixTheme, - child: MixBuilder( - style: StyleMix(), - builder: (mix) { - return Container( - margin: edgeInsetsDto.resolve(mix), - padding: edgeInsetsDto.merge(overrideEdgeInsets).resolve(mix), - child: const SizedBox(width: 50, height: 50), - ); - }, - ), - ); - }), - )); - - final container = tester.findWidgetOfType(); - // final container = tester.widget(widgetFinder); - - // Get BuildContext for boxWidget - final context = tester.findWidgetContext(); - - expect( - container.margin, - EdgeInsets.only( - top: MixTokenResolver(context).space($space.small), - left: MixTokenResolver(context).space($space.xlarge), - bottom: 4.0, - right: 4.0, - ), - ); - - expect( - container.padding, - EdgeInsets.only( - top: MixTokenResolver(context).space($space.small), - bottom: MixTokenResolver(context).space($space.medium), - right: MixTokenResolver(context).space($space.xxlarge), - left: 20, - ), - ); - }); - }); -} diff --git a/test/factory/mix_factory_test.dart b/test/factory/mix_factory_test.dart deleted file mode 100644 index d1a6706a2..000000000 --- a/test/factory/mix_factory_test.dart +++ /dev/null @@ -1,135 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:mix/mix.dart'; -import 'package:mix/src/dtos/color.dto.dart'; -import 'package:mix/src/dtos/edge_insets/edge_insets.dto.dart'; - -final firstMix = StyleMix( - // Box attribute - backgroundColor(Colors.blue), - // Text attribute - textStyle(color: Colors.red), - // Shared attribute - animation(), - // Flex Attribute - gap(10), - // Icon Attribute - iconColor(Colors.green), - // Variant Attribute - onDark(margin(10)), - animationDuration(1000), - padding(0), - margin(0), - width(100), - height(100), - minWidth(100), -); - -final secondMix = StyleMix( - // Box attribute - padding(10), - // Text attribute - textStyle(fontSize: 10), - // Shared attribute - hide(), - // Flex Attribute - mainAxisAlignment(MainAxisAlignment.center), - - // Icon Attribute - iconSize(10), - // Variant Attribute - onHover(width(100)), - onFocus(height(100)), - iconColor(Colors.red), -); - -final nestedMix = StyleMix().mergeMany([ - firstMix, - secondMix, -]); - -void main() { - group("Mix Factory", () { - test('Creates a Mix from positional Attributes', () async { - final style = StyleMix( - backgroundColor(Colors.red), - margin(10), - ); - - final boxAttribute = - style.values.attributesOfType()!; - - // Length is only 1 because margin and color are BoxAttributes - expect(style.values.length, 1); - - expect(boxAttribute.color, const ColorDto(Colors.red)); - expect(boxAttribute.margin, const EdgeInsetsDto.all(10)); - }); - - test('Creates a Mix from Attributes List', () async { - final mix = StyleMix.fromAttributes([ - backgroundColor(Colors.red), - margin(10), - ]); - - final boxAttribute = - mix.values.attributesOfType()!; - - // Length is only 1 because margin and color are BoxAttributes - expect(mix.values.length, 1); - - expect(boxAttribute.color, const ColorDto(Colors.red)); - expect(boxAttribute.margin, const EdgeInsetsDto.all(10)); - }); - }); - - test('Combines Mixes', () async { - const boxAttribute = - StyledContainerAttributes(color: ColorDto(Colors.blue)); - - const flexAttribute = StyledFlexAttributes(direction: Axis.horizontal); - - final baseMix = StyleMix(boxAttribute); - final appliedMix = baseMix.merge(StyleMix(flexAttribute)); - - final modifiedBoxAttribute = - appliedMix.values.attributesOfType(); - - final modifiedFlexAttribute = - appliedMix.values.attributesOfType(); - - expect(baseMix.values.length, 1); - expect(appliedMix.values.length, 2); - - expect(modifiedBoxAttribute, equals(boxAttribute)); - expect(modifiedFlexAttribute, equals(flexAttribute)); - }); - - test('Equality of Mix', () async { - final copyFirstMix = StyleMix.fromAttributes(firstMix.toAttributes()); - final copySecondMix = StyleMix.fromAttributes(secondMix.toAttributes()); - final combinedMixFirst = StyleMix.combine([firstMix, secondMix]); - final combinedMixSecond = firstMix.merge(secondMix); - - expect(copyFirstMix, equals(firstMix)); - expect(copySecondMix, equals(secondMix)); - expect(combinedMixFirst, equals(combinedMixSecond)); - }); - - test('Chooses Mixes based on conditional', () async { - final chooseFirstMix = StyleMix.chooser( - condition: true, - ifTrue: firstMix, - ifFalse: secondMix, - ); - - final chooseSecondMix = StyleMix.chooser( - condition: false, - ifTrue: firstMix, - ifFalse: secondMix, - ); - - expect(chooseFirstMix, firstMix); - expect(chooseSecondMix, secondMix); - }); -} diff --git a/test/factory/mix_provider_test.dart b/test/factory/mix_provider_test.dart deleted file mode 100644 index 30f41a089..000000000 --- a/test/factory/mix_provider_test.dart +++ /dev/null @@ -1,66 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:mix/mix.dart'; -import 'package:mix/src/factory/mix_provider.dart'; - -import '../helpers/random_dto.dart'; - -const textVariant = StyleVariant('textVariant'); - -final overrideTextAttribute = StyledTextAttributes.fromValues( - style: const TextStyle( - fontSize: 18, - color: Colors.blue, - ), -); - -final pressableMix = StyleMix.fromAttributes([ - RandomGenerator.boxAttributes(), - RandomGenerator.textAttributes(), - textVariant(overrideTextAttribute), -]); - -void main() { - group("Mix Provider", () { - testWidgets('Mix Provider exist and Matches', (tester) async { - await tester.pumpWidget( - StyledContainer( - style: pressableMix, - ), - ); - - final widgetFinder = find.byType(MixedContainer); - - // Get BuildContext for boxWidget - BuildContext context = tester.element(widgetFinder); - - // Grab the MixContext from the BoxMixedWidget MixContext.of(context) - final mix = MixProvider.of(context); - - final matchMix = MixData.create( - context: context, - style: pressableMix, - ); - - final clonedMix = MixData.create( - context: context, - style: pressableMix.clone(), - ); - - expect(mix, matchMix); - - expect( - mix, - matchMix, - reason: 'MixValues should be the same', - ); - - // Different instance but same properties - expect(matchMix.hashCode == mix.hashCode, true); - expect(clonedMix.hashCode == mix.hashCode, false); - expect(matchMix, equals(mix), reason: "matchMix should be the same"); - expect(clonedMix, equals(mix), reason: "clonedMix should be the same"); - expect(widgetFinder, findsOneWidget); - }); - }); -} diff --git a/test/factory/mix_values_test.dart b/test/factory/mix_values_test.dart deleted file mode 100644 index 98efac7c4..000000000 --- a/test/factory/mix_values_test.dart +++ /dev/null @@ -1,108 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; // importing flutter_test package -import 'package:mix/src/attributes/attribute.dart'; -import 'package:mix/src/factory/style_mix_data.dart'; -import 'package:mix/src/variants/utilities/context_variant_utilities.dart'; -import 'package:mix/src/variants/variant.dart'; -import 'package:mix/src/variants/variant_attribute.dart'; - -import '../helpers/random_dto.dart'; - -void main() { - group('MixValues', () { - test('Creates empty values', () { - const mixValues = StyleMixData.empty(); - expect(mixValues.attributes, isNull); - - expect(mixValues.variants, isEmpty); - expect(mixValues.contextVariants, isEmpty); - - expect(mixValues.length, equals(0)); - expect(mixValues.hasAttributes, isFalse); - expect(mixValues.hasVariants, isFalse); - expect(mixValues.hasContextVariants, isFalse); - }); - - final attributeList = [ - RandomGenerator.boxAttributes(), - RandomGenerator.boxAttributes(), - RandomGenerator.textAttributes(), - ]; - final variantList = [ - VariantAttribute( - const StyleVariant('testVariant'), - RandomGenerator.mix(), - ), - VariantAttribute( - const StyleVariant('anotherTestVariant'), - RandomGenerator.mix(), - ), - ]; - final contextVariantList = [ - ContextVariantUtilities.onDark()( - RandomGenerator.textAttributes(), - RandomGenerator.boxAttributes(), - ), - ContextVariantUtilities.onLarge()( - RandomGenerator.textAttributes(), - RandomGenerator.boxAttributes(), - ), - ]; - - test('Valid Length Counts', () { - final mixValues = StyleMixData.create( - [...attributeList, ...variantList, ...contextVariantList], - ); - - expect(mixValues.length, equals(6)); - expect(mixValues.hasAttributes, isTrue); - expect(mixValues.hasVariants, isTrue); - expect(mixValues.hasContextVariants, isTrue); - - expect(mixValues.attributes?.length, equals(2)); - expect(mixValues.variants.length, equals(2)); - expect(mixValues.contextVariants.length, equals(2)); - }); - - test('Create from attribute list', () { - final mixValues = StyleMixData.create([ - ...attributeList, - ...variantList, - ...contextVariantList, - ]); - - expect(mixValues.length, equals(6)); - expect(mixValues.hasAttributes, isTrue); - expect(mixValues.hasVariants, isTrue); - expect(mixValues.hasContextVariants, isTrue); - - expect(mixValues.attributes?.length, equals(2)); - expect(mixValues.variants.length, equals(2)); - expect(mixValues.contextVariants.length, equals(2)); - }); - - test('Merge Mix values', () { - final mixValues = StyleMixData.create([ - ...attributeList, - ...variantList, - ...contextVariantList, - ]); - - final otherMixValues = StyleMixData.create([ - ...attributeList, - ...variantList, - ...contextVariantList, - ]); - - final mergedMixValues = mixValues.merge(otherMixValues); - - expect(mergedMixValues.length, equals(10)); - expect(mergedMixValues.hasAttributes, isTrue); - expect(mergedMixValues.hasVariants, isTrue); - expect(mergedMixValues.hasContextVariants, isTrue); - - expect(mergedMixValues.attributes?.length, equals(2)); - expect(mergedMixValues.variants.length, equals(4)); - expect(mergedMixValues.contextVariants.length, equals(4)); - }); - }); -} diff --git a/test/helpers/attribute_generator.dart b/test/helpers/attribute_generator.dart new file mode 100644 index 000000000..6d1c11d23 --- /dev/null +++ b/test/helpers/attribute_generator.dart @@ -0,0 +1,358 @@ +// Used mostly for testing + +import 'dart:math'; + +import 'package:flutter/material.dart'; +import 'package:mix/mix.dart'; + +class AttributeGenerator { + const AttributeGenerator(); + + PaddingAttribute padding({ + double? top, + double? bottom, + double? left, + double? right, + }) { + final random = Random(); + + return PaddingAttribute( + top: top ?? random.nextDouble() * 20, + bottom: bottom ?? random.nextDouble() * 20, + left: left ?? random.nextDouble() * 20, + right: right ?? random.nextDouble() * 20, + ); + } + + BoxConstraintsAttribute boxConstraints({ + double? width, + double? height, + double? minWidth, + double? maxWidth, + double? minHeight, + double? maxHeight, + }) { + final random = Random(); + + minWidth ??= random.nextDouble() * 200; + minHeight ??= random.nextDouble() * 200; + + maxHeight ??= minWidth + random.nextDouble() * 200; + maxWidth ??= minHeight + random.nextDouble() * 200; + + return BoxConstraintsAttribute( + width: width, + height: height, + minWidth: minWidth, + maxWidth: maxWidth, + minHeight: minHeight, + maxHeight: maxHeight, + ); + } + + MarginAttribute margin({ + double? top, + double? bottom, + double? left, + double? right, + }) { + final random = Random(); + + return MarginAttribute( + top: top ?? random.nextDouble() * 20, + bottom: bottom ?? random.nextDouble() * 20, + left: left ?? random.nextDouble() * 20, + right: right ?? random.nextDouble() * 20, + ); + } + + TransformAttribute transform({ + double? x, + double? y, + double? z, + }) { + final random = Random(); + + return Matrix4.translationValues( + x ?? random.nextDouble() * 20, + y ?? random.nextDouble() * 20, + z ?? random.nextDouble() * 20, + ).toAttribute(); + } + + ClipAttribute clip([Clip? clip]) { + return clip?.toAttribute() ?? + Random().randomElement([ + Clip.none, + Clip.antiAlias, + Clip.antiAliasWithSaveLayer, + Clip.hardEdge, + ]).toAttribute(); + } + + TextOverflowAttribute overflow([TextOverflow? overflow]) { + return overflow?.toAttribute() ?? + Random().randomElement([ + TextOverflow.clip, + TextOverflow.visible, + ]).toAttribute(); + } + + TextDirectionAttribute textDirection([TextDirection? direction]) { + return direction?.toAttribute() ?? + Random().randomElement([ + TextDirection.ltr, + TextDirection.rtl, + ]).toAttribute(); + } + + AxisAttribute axis([Axis? axis]) { + return axis?.toAttribute() ?? + Random().randomElement([ + Axis.horizontal, + Axis.vertical, + ]).toAttribute(); + } + + MainAxisAlignmentAttribute mainAxisAlignment([MainAxisAlignment? alignment]) { + return alignment?.toAttribute() ?? + Random().randomElement([ + MainAxisAlignment.start, + MainAxisAlignment.end, + MainAxisAlignment.center, + MainAxisAlignment.spaceBetween, + MainAxisAlignment.spaceAround, + MainAxisAlignment.spaceEvenly, + ]).toAttribute(); + } + + MainAxisSizeAttribute mainAxisSize([MainAxisSize? size]) { + return size?.toAttribute() ?? + Random().randomElement([ + MainAxisSize.max, + MainAxisSize.min, + ]).toAttribute(); + } + + CrossAxisAlignmentAttribute crossAxisAlignment( + [CrossAxisAlignment? alignment]) { + return alignment?.toAttribute() ?? + Random().randomElement([ + CrossAxisAlignment.start, + CrossAxisAlignment.end, + CrossAxisAlignment.center, + CrossAxisAlignment.stretch, + CrossAxisAlignment.baseline, + ]).toAttribute(); + } + + TextBaselineAttribute textBaseline([TextBaseline? baseline]) { + return baseline?.toAttribute() ?? + Random().randomElement([ + TextBaseline.alphabetic, + TextBaseline.ideographic, + ]).toAttribute(); + } + + VerticalDirectionAttribute verticalDirection([VerticalDirection? direction]) { + return direction?.toAttribute() ?? + Random().randomElement([ + VerticalDirection.down, + VerticalDirection.up, + ]).toAttribute(); + } + + BorderRadiusAttribute borderRadius({ + double? topLeft, + double? topRight, + double? bottomLeft, + double? bottomRight, + }) { + final random = Random(); + + return BorderRadiusAttribute( + topLeft: Radius.circular(topLeft ?? random.nextDouble() * 20), + topRight: Radius.circular(topRight ?? random.nextDouble() * 20), + bottomLeft: Radius.circular(bottomLeft ?? random.nextDouble() * 20), + bottomRight: Radius.circular(bottomRight ?? random.nextDouble() * 20), + ); + } + + BorderRadiusDirectionalAttribute borderRadiusDirectional({ + double? topStart, + double? topEnd, + double? bottomStart, + double? bottomEnd, + }) { + final random = Random(); + + return BorderRadiusDirectionalAttribute( + topStart: Radius.circular(topStart ?? random.nextDouble() * 20), + topEnd: Radius.circular(topEnd ?? random.nextDouble() * 20), + bottomStart: Radius.circular(bottomStart ?? random.nextDouble() * 20), + bottomEnd: Radius.circular(bottomEnd ?? random.nextDouble() * 20), + ); + } + + BorderAttribute border({ + BorderSideAttribute? left, + BorderSideAttribute? right, + BorderSideAttribute? top, + BorderSideAttribute? bottom, + }) { + return BorderAttribute( + left: left ?? borderSide(), + right: right ?? borderSide(), + top: top ?? borderSide(), + bottom: bottom ?? borderSide(), + ); + } + + ColorAttribute color([Color? color]) { + return ColorAttribute( + color ?? + Color.fromARGB( + 255, + Random().nextInt(255), + Random().nextInt(255), + Random().nextInt(255), + ), + ); + } + + BorderSideAttribute borderSide({ + ColorAttribute? color, + double? width, + BorderStyle? style, + }) { + return BorderSideAttribute( + color: color ?? this.color(), + width: width ?? Random().nextDouble() * 4, + style: style ?? BorderStyle.values.random(), + ); + } + + ShadowAttribute shadow({ + ColorAttribute? color, + Offset? offset, + double? blurRadius, + }) { + return ShadowAttribute( + color: color ?? this.color(), + offset: offset ?? const Offset(0, 0), + blurRadius: blurRadius ?? Random().nextDouble() * 4, + ); + } + + AlignmentAttribute alignment() { + return Random().randomElement([ + Alignment.center, + Alignment.centerLeft, + Alignment.centerRight, + Alignment.topCenter, + Alignment.topLeft, + Alignment.topRight, + Alignment.bottomCenter, + Alignment.bottomLeft, + Alignment.bottomRight, + ]).toAttribute(); + } + + BoxDecorationAttribute boxDecoration({ + ColorAttribute? color, + BorderAttribute? border, + BorderRadiusAttribute? borderRadius, + List? boxShadow, + BoxShapeAttribute? shape, + }) { + return BoxDecorationAttribute( + color: color ?? this.color(), + border: border ?? this.border(), + borderRadius: borderRadius ?? this.borderRadius(), + boxShadow: boxShadow ?? + [ + this.boxShadow(), + ], + shape: shape ?? BoxShape.values.random().toAttribute(), + ); + } + + BoxShadowAttribute boxShadow({ + ColorAttribute? color, + Offset? offset, + double? blurRadius, + double? spreadRadius, + }) { + return BoxShadowAttribute( + color: color ?? this.color(), + offset: offset ?? + Offset( + Random().nextMaxDouble(10), + Random().nextMaxDouble(10), + ), + blurRadius: blurRadius ?? Random().nextMaxDouble(10), + spreadRadius: spreadRadius ?? Random().nextMaxDouble(10), + ); + } + + TextStyleAttribute textStyle() { + return TextStyleAttribute( + color: color(), + backgroundColor: color(), + decorationColor: color(), + decorationStyle: TextDecorationStyle.values.random(), + fontFamily: 'Roboto', + fontSize: Random().nextDoubleInRange(12, 32), + fontStyle: FontStyle.values.random(), + fontWeight: FontWeight.values.random(), + letterSpacing: Random().nextDoubleInRange(0, 2), + wordSpacing: Random().nextDoubleInRange(0, 2), + height: Random().nextDoubleInRange(0, 2), + locale: const Locale('en', 'US'), + shadows: [ + shadow(), + ], + decoration: [ + TextDecoration.none, + TextDecoration.underline, + TextDecoration.lineThrough, + TextDecoration.overline, + ].random(), + ); + } +} + +extension RandomExt on Random { + T randomElement(List list) { + if (list.isEmpty) throw StateError('List is empty'); + + return list[nextInt(list.length)]; + } + + T? randomElementOrNull(List list) { + return list.isEmpty ? null : randomElement(list); + } + + T randomElementOr(List list, T or) { + return list.isEmpty ? or : randomElement(list); + } + + double nextDoubleInRange(double min, double max) { + return min + nextDouble() * (max - min); + } + + int nextIntInRange(int min, int max) { + return min + nextInt(max - min); + } + + // Returns a double within the max value range. + double nextMaxDouble(double max) { + return nextDoubleInRange(0, max); + } +} + +extension ListRandomExt on List { + T random() { + return Random().randomElement(this); + } +} diff --git a/test/helpers/equatable_mixin_test.dart b/test/helpers/equatable_mixin_test.dart index 79b5e6539..17fbedc7d 100644 --- a/test/helpers/equatable_mixin_test.dart +++ b/test/helpers/equatable_mixin_test.dart @@ -1,5 +1,5 @@ import 'package:flutter_test/flutter_test.dart'; -import 'package:mix/src/helpers/equality_mixin/equality_mixin.dart'; +import 'package:mix/src/core/equality/compare_mixin.dart'; void main() { group('EquatableMixin', () { @@ -105,7 +105,7 @@ void main() { }); } -class TestClass with EqualityMixin { +class TestClass with Comparable { final int id; final String name; @@ -115,7 +115,7 @@ class TestClass with EqualityMixin { List get props => [id, name]; } -class DeepNestedClass with EqualityMixin { +class DeepNestedClass with Comparable { final Map> deepNestedMap; final List>> deepNestedList; diff --git a/test/helpers/random_dto.dart b/test/helpers/random_dto.dart deleted file mode 100644 index 900ec1fba..000000000 --- a/test/helpers/random_dto.dart +++ /dev/null @@ -1,271 +0,0 @@ -// Used mostly for testing - -import 'dart:math'; - -import 'package:flutter/material.dart'; -import 'package:mix/src/dtos/border/border.dto.dart'; -import 'package:mix/src/dtos/border/border_side.dto.dart'; -import 'package:mix/src/dtos/color.dto.dart'; -import 'package:mix/src/dtos/edge_insets/edge_insets.dto.dart'; -import 'package:mix/src/dtos/radius/border_radius.dto.dart'; -import 'package:mix/src/dtos/radius/radius_dto.dart'; -import 'package:mix/src/dtos/shadow/box_shadow.dto.dart'; -import 'package:mix/src/dtos/shadow/shadow.dto.dart'; -import 'package:mix/src/dtos/text_style.dto.dart'; -import 'package:mix/src/factory/style_mix.dart'; -import 'package:mix/src/widgets/container/container.attributes.dart'; -import 'package:mix/src/widgets/text/text.attributes.dart'; -import 'package:mix/src/widgets/text/text_directives/text_directives.dart'; - -class RandomGenerator { - const RandomGenerator._(); - static StyledTextAttributes textAttributes() { - return StyledTextAttributes( - style: textStyleDto(), - textAlign: TextAlign.values.random(), - softWrap: Random().nextBool(), - overflow: TextOverflow.values.random(), - textWidthBasis: TextWidthBasis.values.random(), - textHeightBehavior: const TextHeightBehavior(), - directives: [ - const UppercaseDirective(), - const LowercaseDirective(), - const CapitalizeDirective(), - const SentenceCaseDirective(), - ], - ); - } - - static StyleMix mix() { - return StyleMix( - textAttributes(), - textAttributes(), - boxAttributes(), - boxAttributes(), - ); - } - - static StyledContainerAttributes boxAttributes({ - bool someNullable = true, - }) { - final margin = edgeInsetsDto(); - - final padding = edgeInsetsDto(); - - final alignment = Random().randomElement([ - Alignment.center, - Alignment.centerLeft, - Alignment.centerRight, - Alignment.topCenter, - Alignment.topLeft, - Alignment.topRight, - Alignment.bottomCenter, - Alignment.bottomLeft, - Alignment.bottomRight, - ]); - - final height = Random().nextMaxDouble(500); - - final width = Random().nextMaxDouble(500); - - final color = colorDto(); - - final border = borderDto(); - - final borderRadius = borderRadiusDto(); - - final boxShadow = [ - boxShadowDto(), - boxShadowDto(), - boxShadowDto(), - boxShadowDto(), - ]; - - final maxHeight = Random().nextMaxDouble(500); - - final minHeight = Random().nextMaxDouble(maxHeight); - - final maxWidth = Random().nextMaxDouble(500); - - final minWidth = Random().nextMaxDouble(maxWidth); - - final shape = Random().randomElement(BoxShape.values); - - final boxAttributes = StyledContainerAttributes( - margin: margin, - padding: padding, - alignment: alignment, - height: height, - width: width, - color: color, - border: border, - borderRadius: borderRadius, - boxShadow: boxShadow, - maxHeight: maxHeight, - minHeight: minHeight, - maxWidth: maxWidth, - minWidth: minWidth, - shape: shape, - ); - - if (someNullable) { - return StyledContainerAttributes( - margin: Random().nextBool() ? margin : null, - padding: Random().nextBool() ? padding : null, - alignment: Random().nextBool() ? alignment : null, - height: Random().nextBool() ? height : null, - width: Random().nextBool() ? width : null, - color: Random().nextBool() ? color : null, - border: Random().nextBool() ? border : null, - borderRadius: Random().nextBool() ? borderRadius : null, - boxShadow: Random().nextBool() ? boxShadow : null, - maxHeight: Random().nextBool() ? maxHeight : null, - minHeight: Random().nextBool() ? minHeight : null, - maxWidth: Random().nextBool() ? maxWidth : null, - minWidth: Random().nextBool() ? minWidth : null, - shape: Random().nextBool() ? shape : null, - ); - } - - return boxAttributes; - } - - static EdgeInsetsDto edgeInsetsDto() { - final random = Random(); - - return EdgeInsetsDto.only( - top: random.nextDouble() * 100, - bottom: random.nextDouble() * 100, - left: random.nextDouble() * 100, - right: random.nextDouble() * 100, - ); - } - - static BorderRadiusDto borderRadiusDto() { - final random = Random(); - - return BorderRadiusDto.only( - topLeft: RadiusDto.circular(random.nextDouble() * 20), - topRight: RadiusDto.circular(random.nextDouble() * 20), - bottomLeft: RadiusDto.circular(random.nextDouble() * 20), - bottomRight: RadiusDto.circular(random.nextDouble() * 20), - ); - } - - static BorderDto borderDto() { - final side = borderSideDto(); - - return BorderDto.only( - top: side, - right: side, - bottom: side, - left: side, - ); - } - - static ColorDto colorDto() { - return ColorDto( - Color.fromARGB( - 255, - Random().nextInt(255), - Random().nextInt(255), - Random().nextInt(255), - ), - ); - } - - static BorderSideDto borderSideDto() { - return BorderSideDto.only( - color: colorDto(), - width: Random().nextDouble() * 4, - style: BorderStyle.values.random(), - ); - } - - static ShadowDto shadowDto() { - return ShadowDto( - color: colorDto(), - offset: Offset( - Random().nextMaxDouble(10), - Random().nextMaxDouble(10), - ), - blurRadius: Random().nextMaxDouble(10), - ); - } - - static BoxShadowDto boxShadowDto() { - // Use shadow as a starting point - final shadow = shadowDto(); - - return BoxShadowDto( - color: shadow.color, - offset: shadow.offset, - blurRadius: shadow.blurRadius, - spreadRadius: Random().nextMaxDouble(10), - ); - } - - static TextStyleDto textStyleDto() { - return TextStyleDto( - color: colorDto(), - backgroundColor: colorDto(), - decorationColor: colorDto(), - decorationStyle: TextDecorationStyle.values.random(), - fontFamily: 'Roboto', - fontSize: Random().nextDoubleInRange(12, 32), - fontStyle: FontStyle.values.random(), - fontWeight: FontWeight.values.random(), - letterSpacing: Random().nextDoubleInRange(0, 2), - wordSpacing: Random().nextDoubleInRange(0, 2), - height: Random().nextDoubleInRange(0, 2), - locale: const Locale('en', 'US'), - shadows: [ - shadowDto(), - shadowDto(), - shadowDto(), - shadowDto(), - ], - decoration: [ - TextDecoration.none, - TextDecoration.underline, - TextDecoration.lineThrough, - TextDecoration.overline, - ].random(), - ); - } -} - -extension RandomExt on Random { - T randomElement(List list) { - if (list.isEmpty) throw StateError('List is empty'); - - return list[nextInt(list.length)]; - } - - T? randomElementOrNull(List list) { - return list.isEmpty ? null : randomElement(list); - } - - T randomElementOr(List list, T or) { - return list.isEmpty ? or : randomElement(list); - } - - double nextDoubleInRange(double min, double max) { - return min + nextDouble() * (max - min); - } - - int nextIntInRange(int min, int max) { - return min + nextInt(max - min); - } - - // Returns a double within the max value range. - double nextMaxDouble(double max) { - return nextDoubleInRange(0, max); - } -} - -extension ListRandomExt on List { - T random() { - return Random().randomElement(this); - } -} diff --git a/test/helpers/string_ext_test.dart b/test/helpers/string_ext_test.dart new file mode 100644 index 000000000..38c39723a --- /dev/null +++ b/test/helpers/string_ext_test.dart @@ -0,0 +1,120 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/src/helpers/extensions/string_ext.dart'; + +void main() { + group('ChangeCase - _groupWords', () { + final cases = { + 'HelloWorld': ['Hello', 'World'], + 'Hello_World': ['Hello', 'World'], + 'Hello-World': ['Hello', 'World'], + 'Hello World': ['Hello', 'World'], + 'helloWorld': ['hello', 'World'], + 'HELLOWORLD': ['HELLOWORLD'], + 'HELLO_WORLD': ['HELLO', 'WORLD'], + 'HELLO-WORLD': ['HELLO', 'WORLD'], + 'HELLO WORLD': ['HELLO', 'WORLD'], + 'HelloWorldHello': ['Hello', 'World', 'Hello'], + '': [], // Edge case: Empty string + 'hello': ['hello'], // Single word + 'Hello': ['Hello'], // Single capitalized word + 'HELLO': ['HELLO'], // Single uppercase word + '12345': ['12345'], // Numbers + 'hello123World': ['hello123', 'World'], // Mix of numbers and letters + '!@#\$%^&*()': ['!@#\$%^&*()'], // Special characters only + 'Hello!World': [ + 'Hello!', + 'World' + ], // Words separated by a non-standard separator + }; + + cases.forEach((input, expectedOutput) { + test('should group words for input: $input', () { + expect(input.words, expectedOutput); + }); + }); + + final paramCases = { + 'HelloWorld': 'hello-world', + 'Hello_World': 'hello-world', + 'Hello-World': 'hello-world', + 'Hello World': 'hello-world', + 'helloWorld': 'hello-world', + 'HELLOWORLD': 'helloworld', + 'HELLO_WORLD': 'hello-world', + 'HELLO-WORLD': 'hello-world', + 'HELLO WORLD': 'hello-world', + 'HelloWorldHello': 'hello-world-hello', + '': '', // Edge case: Empty string + 'hello': 'hello', // Single word + 'Hello': 'hello', // Single capitalized word + 'HELLO': 'hello', // Single uppercase word + '12345': '12345', // Numbers + 'hello123World': 'hello123-world', // Mix of numbers and letters + '!@#\$%^&*()': '!@#\$%^&*()', // Special characters only + 'Hello!World': + 'hello!-world', // Words separated by a non-standard separator + }; + + paramCases.forEach((input, expectedOutput) { + test('should convert to paramCase for input: $input', () { + expect(input.paramCase, expectedOutput); + }); + }); + + final pascalCases = { + 'HelloWorld': 'HelloWorld', + 'Hello_World': 'HelloWorld', + 'Hello-World': 'HelloWorld', + 'Hello World': 'HelloWorld', + 'helloWorld': 'HelloWorld', + 'HELLOWORLD': 'Helloworld', + 'HELLO_WORLD': 'HelloWorld', + 'HELLO-WORLD': 'HelloWorld', + 'HELLO WORLD': 'HelloWorld', + 'HelloWorldHello': 'HelloWorldHello', + '': '', // Edge case: Empty string + 'hello': 'Hello', // Single word + 'Hello': 'Hello', // Single capitalized word + 'HELLO': 'Hello', // Single uppercase word + '12345': '12345', // Numbers + 'hello123World': 'Hello123World', // Mix of numbers and letters + '!@#\$%^&*()': '!@#\$%^&*()', // Special characters only + 'Hello!World': + 'Hello!World', // Words separated by a non-standard separator + }; + + pascalCases.forEach((input, expectedOutput) { + test('should convert to PascalCase for input: $input', () { + expect(input.pascalCase, expectedOutput); + }); + }); + + final camelCases = { + 'HelloWorld': 'helloWorld', + 'Hello_World': 'helloWorld', + 'Hello-World': 'helloWorld', + 'Hello World': 'helloWorld', + 'helloWorld': 'helloWorld', + 'HELLOWORLD': 'helloworld', + 'HELLO_WORLD': 'helloWorld', + 'HELLO-WORLD': 'helloWorld', + 'HELLO WORLD': 'helloWorld', + 'HelloWorldHello': 'helloWorldHello', + '': '', // Edge case: Empty string + 'hello': 'hello', // Single word + 'Hello': 'hello', // Single capitalized word + 'HELLO': 'hello', // Single uppercase word + '12345': '12345', // Numbers + 'hello123World': 'hello123World', // Mix of numbers and letters + '!@#\$%^&*()': '!@#\$%^&*()', // Special characters only + 'Hello!World': + 'hello!World', // Words separated by a non-standard separator + }; + + camelCases.forEach((input, expectedOutput) { + test('should convert to camelCase for input: $input', () { + expect(input.camelCase, expectedOutput); + }); + }); + }); +} diff --git a/test/helpers/testing_utils.dart b/test/helpers/testing_utils.dart index c1b2ac5dc..9b3b75729 100644 --- a/test/helpers/testing_utils.dart +++ b/test/helpers/testing_utils.dart @@ -1,21 +1,154 @@ +// ignore_for_file: non_constant_identifier_names + import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:meta/meta.dart'; import 'package:mix/mix.dart'; +import 'package:mockito/mockito.dart'; -export 'package:mix/src/extensions/helper_ext.dart'; +export 'package:mix/src/helpers/extensions/values_ext.dart'; -class TestMixWidget extends StatelessWidget { - const TestMixWidget({ - required this.child, - Key? key, - }) : super(key: key); +class MockBuildContext extends Mock implements BuildContext {} - final Widget child; +MixData MockMixData( + StyleMix style, +) { + return MixData.create( + MockBuildContext(), + style, + ); +} - @override - Widget build(BuildContext context) { - return Directionality( - textDirection: TextDirection.ltr, - child: child, +final EmptyMixData = MixData.create( + MockBuildContext(), + StyleMix.empty, +); + +MediaQuery createMediaQuery(Size size) { + return MediaQuery( + data: MediaQueryData(size: size), + child: MixTheme( + data: MixThemeData(), + child: MaterialApp( + home: Scaffold( + body: Builder( + builder: (BuildContext context) { + return Container(); + }, + ), + ), + ), + ), + ); +} + +Widget createBrightnessTheme(Brightness brightness) { + return MixTheme( + data: MixThemeData(), + child: MaterialApp( + theme: ThemeData(brightness: brightness), + home: Scaffold( + body: Builder( + builder: (BuildContext context) { + return Container(); + }, + ), + ), + ), + ); +} + +Widget createDirectionality(TextDirection direction) { + return MixTheme( + data: MixThemeData(), + child: MaterialApp( + home: Directionality( + textDirection: direction, + child: Scaffold( + body: Builder( + builder: (BuildContext context) { + return Container(); + }, + ), + ), + ), + ), + ); +} + +Widget createWithMixTheme( + MixThemeData theme, +) { + return MixTheme( + data: theme, + child: MaterialApp( + home: Scaffold( + body: Builder( + builder: (BuildContext context) { + return Container(); + }, + ), + ), + ), + ); +} + +extension WidgetTesterExt on WidgetTester { + Future pumpWithMix( + Widget widget, { + StyleMix style = StyleMix.empty, + MixThemeData theme = const MixThemeData.empty(), + }) async { + await pumpWidget( + MaterialApp( + home: MixTheme( + data: theme, + child: Builder( + builder: (BuildContext context) { + // Populate MixData into the widget tree if needed + return Mix.build(context, style: style, builder: (_) => widget); + }, + ), + ), + ), + ); + } + + Future pumpWithPressable( + Widget widget, { + PressableState state = PressableState.pressed, + bool focus = false, + }) async { + await pumpWidget( + MaterialApp( + home: PressableNotifier( + state: state, + focus: focus, + child: widget, + ), + ), + ); + } + + Future pumpMaterialApp(Widget widget) async { + await pumpWidget( + MaterialApp( + home: widget, + ), + ); + } + + Future pumpStyledWidget( + StyledWidget widget, { + MixThemeData theme = const MixThemeData.empty(), + }) async { + await pumpWidget( + MaterialApp( + home: MixTheme( + data: theme, + child: widget, + ), + ), ); } } @@ -48,46 +181,126 @@ class WrapMixThemeWidget extends StatelessWidget { } } -class BoxInsideFlexWidget extends StatelessWidget { - const BoxInsideFlexWidget(this.mix, {Key? key}) : super(key: key); +class MockDoubleScalarAttribute + extends ScalarAttribute { + const MockDoubleScalarAttribute(super.value); + + @override + MockDoubleScalarAttribute create(double value) => + MockDoubleScalarAttribute(value); +} - final StyleMix mix; +class MockIntScalarAttribute + extends ScalarAttribute { + const MockIntScalarAttribute(super.value); @override - Widget build(BuildContext context) { - return TestMixWidget( - child: Column( - children: [ - StyledContainer( - style: mix, - child: FillWidget, - ), - ], - ), + MockIntScalarAttribute create(int value) => MockIntScalarAttribute(value); +} + +class MockDoubleDecoratorAttribute extends Decorator { + final double value; + const MockDoubleDecoratorAttribute(this.value); + + @override + MockDoubleDecoratorAttribute merge(MockDoubleDecoratorAttribute? other) { + return MockDoubleDecoratorAttribute(other?.value ?? value); + } + + @override + double resolve(MixData mix) => value; + + @override + get props => [value]; + + @override + Widget build(child, value) { + return SizedBox( + height: value, + width: value, + child: child, ); } } -class BoxTestWidget extends StatelessWidget { - const BoxTestWidget( - this.mix, { - Key? key, - double? height, - double? width, - }) : super(key: key); +class MockBooleanScalarAttribute + extends ScalarAttribute { + const MockBooleanScalarAttribute(super.value); - final StyleMix mix; + @override + MockBooleanScalarAttribute create(bool value) => + MockBooleanScalarAttribute(value); +} + +class MockStringScalarAttribute + extends ScalarAttribute { + const MockStringScalarAttribute(super.value); @override - Widget build(BuildContext context) { - return TestMixWidget( - child: StyledContainer( - style: mix, - child: const SizedBox( - height: 25, - width: 25, - ), - ), - ); + MockStringScalarAttribute create(String value) => + MockStringScalarAttribute(value); +} + +class MockInvalidAttribute extends Attribute { + const MockInvalidAttribute(); + + @override + get props => []; + + @override + MockInvalidAttribute merge(MockInvalidAttribute? other) { + return this; } } + +const mockVariant = Variant('mock-variant'); + +@isTestGroup +void testScalarAttribute, V>( + String groupName, + T Function(V value) builder, + List values, +) { + group(groupName, () { + for (var value1 in values) { + for (var value2 in values.where((v) => v != value1)) { + test('merge $value1 with $value2', () { + final attr1 = builder(value1); + final attr2 = builder(value2); + final merged = attr1.merge(attr2); + expect(merged.value, equals(value2)); + }); + + test('resolve $value1', () { + final attr = builder(value1); + final resolvedValue = attr.resolve(EmptyMixData); + expect(resolvedValue, equals(value1)); + }); + + test('check equality between $value1 and $value2', () { + final attr1 = builder(value1); + final attr2 = builder(value2); + expect(attr1, isNot(equals(attr2))); + }); + + test('check self-equality for $value1', () { + final attr1 = builder(value1); + final attr2 = builder(value1); + expect(attr1, equals(attr2)); + }); + } + + test('merge null with $value1 returns itself', () { + final attr1 = builder(value1); + final merged = attr1.merge(null); + expect(merged, equals(attr1)); + }); + + test('resolves correctly', () { + final attr = builder(value1); + final resolvedValue = attr.resolve(EmptyMixData); + expect(resolvedValue, equals(value1)); + }); + } + }); +} diff --git a/test/src/attributes/alignment_attribute_test.dart b/test/src/attributes/alignment_attribute_test.dart new file mode 100644 index 000000000..d6611f131 --- /dev/null +++ b/test/src/attributes/alignment_attribute_test.dart @@ -0,0 +1,154 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/src/attributes/alignment_attribute.dart'; + +import '../../helpers/testing_utils.dart'; + +void main() { + group('AlignmentAttribute', () { + test('class resolves correctly', () { + const alignment = AlignmentAttribute(x: 0.5, y: 0.6); + + final resolvedValue = alignment.resolve(EmptyMixData); + + expect(alignment, isA()); + expect(alignment, isA()); + expect(resolvedValue, isA()); + expect(resolvedValue.x, 0.5); + expect(resolvedValue.y, 0.6); + }); + test('merge returns merged object correctly', () { + const attr1 = AlignmentAttribute(x: 0.1, y: 0.2); + const attr2 = AlignmentAttribute(x: 0.3); + + final merged = attr1.merge(attr2); + + final resolvedValue = merged.resolve(EmptyMixData); + + expect(resolvedValue.x, 0.3); // should take from attr2 + expect(resolvedValue.y, 0.2); // should take from attr1 + expect(resolvedValue, isA()); + }); + + test('AlignmentAttribute merge returns itself if other is null', () { + const attr1 = AlignmentAttribute(x: 0.1, y: 0.2); + + final merged = attr1.merge(null); + + expect(merged, attr1); + }); + + test( + 'AlignmentAttribute resolve returns correct Alignment', + () { + const attr = AlignmentAttribute(x: 0.5, y: 0.5); + + final alignment = attr.resolve(EmptyMixData); + + expect(alignment, const Alignment(0.5, 0.5)); + }, + ); + + test( + 'AlignmentAttribute resolve uses default values if null', + () { + const attr = AlignmentAttribute(); + + final alignment = attr.resolve(EmptyMixData); + + expect(alignment, const Alignment(0.0, 0.0)); + }, + ); + + test('AlignmentAttribute equality holds when properties are the same', () { + const attr1 = AlignmentAttribute(x: 0.1, y: 0.2); + const attr2 = AlignmentAttribute(x: 0.1, y: 0.2); + + expect(attr1, attr2); + }); + + test('AlignmentAttribute equality fails when properties are different', () { + const attr1 = AlignmentAttribute(x: 0.1, y: 0.2); + const attr2 = AlignmentAttribute(x: 0.2, y: 0.2); + + expect(attr1, isNot(attr2)); + }); + }); + + group('AlignmentDirectionalAttribute', () { + test('class resolves correctly', () { + const alignment = AlignmentDirectionalAttribute(start: 0.5, y: 0.6); + + final resolvedValue = alignment.resolve(EmptyMixData); + + expect(alignment, isA()); + expect(alignment, isA()); + expect(resolvedValue, isA()); + expect(resolvedValue, isA()); + expect(resolvedValue.start, 0.5); + expect(resolvedValue.y, 0.6); + }); + + test('merge returns merged object correctly', () { + const attr1 = AlignmentDirectionalAttribute(start: 0.1, y: 0.2); + const attr2 = AlignmentDirectionalAttribute(start: 0.3); + + final merged = attr1.merge(attr2); + + final resolvedValue = merged.resolve(EmptyMixData); + + expect(resolvedValue.start, 0.3); // should take from attr2 + expect(resolvedValue.y, 0.2); // should take from attr1 + expect(resolvedValue, isA()); + }); + + test('AlignmentDirectionalAttribute merge returns itself if other is null', + () { + const attr1 = AlignmentDirectionalAttribute(start: 0.1, y: 0.2); + + final merged = attr1.merge(null); + + expect(merged, attr1); + }); + + test( + 'AlignmentDirectionalAttribute resolve returns correct AlignmentDirectional', + () { + const attr = AlignmentDirectionalAttribute(start: 0.5, y: 0.5); + + final alignment = attr.resolve(EmptyMixData); + + expect(alignment, const AlignmentDirectional(0.5, 0.5)); + }, + ); + + test( + 'AlignmentDirectionalAttribute resolve uses default values if null', + () { + const attr = AlignmentDirectionalAttribute(); + + final alignment = attr.resolve(EmptyMixData); + + expect(alignment, const AlignmentDirectional(0.0, 0.0)); + }, + ); + + test( + 'AlignmentDirectionalAttribute equality holds when properties are the same', + () { + const attr1 = AlignmentDirectionalAttribute(start: 0.1, y: 0.2); + const attr2 = AlignmentDirectionalAttribute(start: 0.1, y: 0.2); + + expect(attr1, attr2); + }); + + test( + 'AlignmentDirectionalAttribute equality fails when properties are different', + () { + const attr1 = AlignmentDirectionalAttribute(start: 0.1, y: 0.2); + const attr2 = AlignmentDirectionalAttribute(start: 0.2, y: 0.2); + + expect(attr1, isNot(attr2)); + }); + }); +} diff --git a/test/src/attributes/border/border_attribute_test.dart b/test/src/attributes/border/border_attribute_test.dart new file mode 100644 index 000000000..7700df843 --- /dev/null +++ b/test/src/attributes/border/border_attribute_test.dart @@ -0,0 +1,221 @@ +import 'package:flutter/rendering.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/src/attributes/border/border_attribute.dart'; + +import '../../../helpers/testing_utils.dart'; + +void main() { + group('BorderAttribute', () { + test('merge should combine two BorderAttributes correctly', () { + const borderAttr1 = BorderAttribute( + top: BorderSideAttribute(width: 5.0), + bottom: BorderSideAttribute(width: 10.0), + left: BorderSideAttribute(width: 15.0), + right: BorderSideAttribute(width: 20.0), + ); + const borderAttr2 = BorderAttribute( + left: BorderSideAttribute(width: 25.0), + ); + + final mergedBorderAttr = borderAttr1.merge(borderAttr2); + + expect(mergedBorderAttr.top, borderAttr1.top); + expect(mergedBorderAttr.bottom, borderAttr1.bottom); + expect(mergedBorderAttr.left, borderAttr2.left); + expect(mergedBorderAttr.right, borderAttr1.right); + }); + + test('resolve should create a Border with the correct values', () { + const borderAttr = BorderAttribute( + top: BorderSideAttribute(width: 5.0), + bottom: BorderSideAttribute(width: 10.0), + left: BorderSideAttribute(width: 15.0), + right: BorderSideAttribute(width: 20.0), + ); + + final resolvedBorder = borderAttr.resolve(EmptyMixData); + + expect(resolvedBorder.top, const BorderSide(width: 5.0)); + expect(resolvedBorder.bottom, const BorderSide(width: 10.0)); + expect(resolvedBorder.left, const BorderSide(width: 15.0)); + expect(resolvedBorder.right, const BorderSide(width: 20.0)); + }); + + test('Equality holds when properties are the same', () { + const attr1 = BorderAttribute( + top: BorderSideAttribute(width: 5.0), + bottom: BorderSideAttribute(width: 10.0), + left: BorderSideAttribute(width: 15.0), + right: BorderSideAttribute(width: 20.0), + ); + const attr2 = BorderAttribute( + top: BorderSideAttribute(width: 5.0), + bottom: BorderSideAttribute(width: 10.0), + left: BorderSideAttribute(width: 15.0), + right: BorderSideAttribute(width: 20.0), + ); + expect(attr1, attr2); + }); + + test('Equality fails when properties are different', () { + const attr1 = BorderAttribute( + top: BorderSideAttribute(width: 5.0), + bottom: BorderSideAttribute(width: 10.0), + left: BorderSideAttribute(width: 15.0), + right: BorderSideAttribute(width: 20.0), + ); + + const attr2 = BorderAttribute( + top: BorderSideAttribute(width: 5.0), + bottom: BorderSideAttribute(width: 10.0), + left: BorderSideAttribute(width: 15.0), + right: BorderSideAttribute(width: 25.0), + ); + expect(attr1, isNot(attr2)); + }); + }); + + test('Matches Border constructors', () { + const allAttr = BorderAttribute.all(BorderSideAttribute(width: 10.0)); + final allValue = Border.all(width: 10.0); + + final resolvedAllValue = allAttr.resolve(EmptyMixData); + + expect(resolvedAllValue, allValue); + + const symmetricAttr = BorderAttribute.symmetric( + vertical: BorderSideAttribute(width: 5.0), + horizontal: BorderSideAttribute(width: 10.0), + ); + + const symmetricValue = Border.symmetric( + vertical: BorderSide(width: 5.0), + horizontal: BorderSide(width: 10.0), + ); + + final resolvedSymmetricValue = symmetricAttr.resolve(EmptyMixData); + + expect(resolvedSymmetricValue, symmetricValue); + + const onlyAttr = BorderAttribute( + top: BorderSideAttribute(width: 5.0), + right: BorderSideAttribute(width: 10.0), + bottom: BorderSideAttribute(width: 15.0), + left: BorderSideAttribute(width: 20.0), + ); + + const onlyValue = Border( + top: BorderSide(width: 5.0), + right: BorderSide(width: 10.0), + bottom: BorderSide(width: 15.0), + left: BorderSide(width: 20.0), + ); + + final resolvedOnlyValue = onlyAttr.resolve(EmptyMixData); + + expect(resolvedOnlyValue, onlyValue); + }); + + group('BorderDirectionalAttribute', () { + test('merge should combine two BorderDirectionalAttributes correctly', () { + const borderAttr1 = BorderDirectionalAttribute( + top: BorderSideAttribute(width: 5.0), + bottom: BorderSideAttribute(width: 10.0), + start: BorderSideAttribute(width: 15.0), + end: BorderSideAttribute(width: 20.0), + ); + const borderAttr2 = BorderDirectionalAttribute( + start: BorderSideAttribute(width: 25.0), + ); + + final mergedBorderAttr = borderAttr1.merge(borderAttr2); + + expect(mergedBorderAttr.top, borderAttr1.top); + expect(mergedBorderAttr.bottom, borderAttr1.bottom); + expect(mergedBorderAttr.start, borderAttr2.start); + expect(mergedBorderAttr.end, borderAttr1.end); + }); + + test('resolve should create a BorderDirectional with the correct values', + () { + const borderAttr = BorderDirectionalAttribute( + top: BorderSideAttribute(width: 5.0), + bottom: BorderSideAttribute(width: 10.0), + start: BorderSideAttribute(width: 15.0), + end: BorderSideAttribute(width: 20.0), + ); + + final resolvedBorder = borderAttr.resolve(EmptyMixData); + + expect(resolvedBorder.top, const BorderSide(width: 5.0)); + expect(resolvedBorder.bottom, const BorderSide(width: 10.0)); + expect(resolvedBorder.start, const BorderSide(width: 15.0)); + expect(resolvedBorder.end, const BorderSide(width: 20.0)); + }); + + test('Equality holds when properties are the same', () { + const attr1 = BorderDirectionalAttribute( + top: BorderSideAttribute(width: 5.0), + bottom: BorderSideAttribute(width: 10.0), + start: BorderSideAttribute(width: 15.0), + end: BorderSideAttribute(width: 20.0), + ); + const attr2 = BorderDirectionalAttribute( + top: BorderSideAttribute(width: 5.0), + bottom: BorderSideAttribute(width: 10.0), + start: BorderSideAttribute(width: 15.0), + end: BorderSideAttribute(width: 20.0), + ); + expect(attr1, attr2); + }); + + test('Equality fails when properties are different', () { + const attr1 = BorderDirectionalAttribute( + top: BorderSideAttribute(width: 5.0), + bottom: BorderSideAttribute(width: 10.0), + start: BorderSideAttribute(width: 15.0), + end: BorderSideAttribute(width: 20.0), + ); + + const attr2 = BorderDirectionalAttribute( + top: BorderSideAttribute(width: 5.0), + bottom: BorderSideAttribute(width: 10.0), + start: BorderSideAttribute(width: 15.0), + end: BorderSideAttribute(width: 25.0), + ); + expect(attr1, isNot(attr2)); + }); + + test('Matches Border constructors', () { + const allAttr = + BorderDirectionalAttribute.all(BorderSideAttribute(width: 10.0)); + const allValue = BorderDirectional( + bottom: BorderSide(width: 10.0), + end: BorderSide(width: 10.0), + start: BorderSide(width: 10.0), + top: BorderSide(width: 10.0), + ); + + final resolvedAllValue = allAttr.resolve(EmptyMixData); + expect(resolvedAllValue, allValue); + + const onlyAttr = BorderDirectionalAttribute( + top: BorderSideAttribute(width: 5.0), + start: BorderSideAttribute(width: 10.0), + end: BorderSideAttribute(width: 15.0), + bottom: BorderSideAttribute(width: 20.0), + ); + + const onlyValue = BorderDirectional( + top: BorderSide(width: 5.0), + start: BorderSide(width: 10.0), + end: BorderSide(width: 15.0), + bottom: BorderSide(width: 20.0), + ); + + final resolvedOnlyValue = onlyAttr.resolve(EmptyMixData); + + expect(resolvedOnlyValue, onlyValue); + }); + }); +} diff --git a/test/src/attributes/border/border_radius_attribute_test.dart b/test/src/attributes/border/border_radius_attribute_test.dart new file mode 100644 index 000000000..a9a34caec --- /dev/null +++ b/test/src/attributes/border/border_radius_attribute_test.dart @@ -0,0 +1,424 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/mix.dart'; + +import '../../../helpers/testing_utils.dart'; + +void main() { + group('BorderRadiusAttribute', () { + test('BorderRadiusAttribute.all', () { + const attr = BorderRadiusAttribute.all(Radius.circular(5.0)); + expect(attr.topLeft, const Radius.circular(5.0)); + expect(attr.topRight, const Radius.circular(5.0)); + expect(attr.bottomLeft, const Radius.circular(5.0)); + expect(attr.bottomRight, const Radius.circular(5.0)); + }); + + test('BorderRadiusAttribute.horizontal', () { + const attr = BorderRadiusAttribute.horizontal( + left: Radius.circular(5.0), + right: Radius.circular(10.0), + ); + + expect(attr.topLeft, const Radius.circular(5.0)); + expect(attr.topRight, const Radius.circular(10.0)); + expect(attr.bottomLeft, const Radius.circular(5.0)); + expect(attr.bottomRight, const Radius.circular(10.0)); + }); + + test('BorderRadiusAttribute.vertical', () { + const attr = BorderRadiusAttribute.vertical( + top: Radius.circular(5.0), + bottom: Radius.circular(10.0), + ); + + expect(attr.topLeft, const Radius.circular(5.0)); + expect(attr.topRight, const Radius.circular(5.0)); + expect(attr.bottomLeft, const Radius.circular(10.0)); + expect(attr.bottomRight, const Radius.circular(10.0)); + }); + + test('BorderRadiusAttribute.circular', () { + final attr = BorderRadiusAttribute.circular(5.0); + expect(attr.topLeft, const Radius.circular(5.0)); + expect(attr.topRight, const Radius.circular(5.0)); + expect(attr.bottomLeft, const Radius.circular(5.0)); + expect(attr.bottomRight, const Radius.circular(5.0)); + }); + + test('merge returns merged object correctly', () { + const attr1 = BorderRadiusAttribute.horizontal( + left: Radius.circular(5.0), + right: Radius.circular(10.0), + ); + const attr2 = BorderRadiusAttribute.vertical( + top: Radius.circular(5.0), + bottom: Radius.circular(10.0), + ); + + final merged = attr1.merge(attr2); + + expect(merged.topLeft, attr2.topLeft); + expect(merged.topRight, attr2.topRight); + expect(merged.bottomLeft, attr2.bottomLeft); + expect(merged.bottomRight, attr2.bottomRight); + }); + + test('merge should combine two BorderRadiusAttributes correctly', () { + const borderRadius1 = BorderRadiusAttribute.all(Radius.circular(10)); + const borderRadius2 = BorderRadiusAttribute( + topLeft: Radius.circular(20), + ); + + final mergedBorderRadius = borderRadius1.merge(borderRadius2); + + expect(mergedBorderRadius.topLeft, const Radius.circular(20)); + expect(mergedBorderRadius.topRight, const Radius.circular(10)); + expect(mergedBorderRadius.bottomLeft, const Radius.circular(10)); + expect(mergedBorderRadius.bottomRight, const Radius.circular(10)); + }); + + test('resolve should create a BorderRadius with the correct values', () { + const borderRadius = BorderRadiusAttribute( + topLeft: Radius.circular(10), + topRight: Radius.circular(20), + bottomLeft: Radius.circular(30), + bottomRight: Radius.circular(40), + ); + + final resolvedBorderRadius = borderRadius.resolve(EmptyMixData); + + expect(resolvedBorderRadius.topLeft, const Radius.circular(10)); + expect(resolvedBorderRadius.topRight, const Radius.circular(20)); + expect(resolvedBorderRadius.bottomLeft, const Radius.circular(30)); + expect(resolvedBorderRadius.bottomRight, const Radius.circular(40)); + }); + + test('Equality holds when properties are the same', () { + const attr1 = BorderRadiusAttribute( + topLeft: Radius.circular(5.0), + topRight: Radius.circular(10.0), + bottomLeft: Radius.circular(15.0), + bottomRight: Radius.circular(20.0), + ); + const attr2 = BorderRadiusAttribute( + topLeft: Radius.circular(5.0), + topRight: Radius.circular(10.0), + bottomLeft: Radius.circular(15.0), + bottomRight: Radius.circular(20.0), + ); + expect(attr1, attr2); + }); + + test('Equality fails when properties are different', () { + const attr1 = BorderRadiusAttribute( + topLeft: Radius.circular(5.0), + topRight: Radius.circular(10.0), + bottomLeft: Radius.circular(15.0), + bottomRight: Radius.circular(20.0), + ); + + const attr2 = BorderRadiusAttribute( + topLeft: Radius.circular(5.0), + topRight: Radius.circular(10.0), + bottomLeft: Radius.circular(15.0), + bottomRight: Radius.circular(25.0), + ); + expect(attr1, isNot(attr2)); + }); + + test('Matches BorderRadius contructors', () { + const allAttr = BorderRadiusAttribute.all(Radius.circular(10.0)); + const allValue = BorderRadius.all(Radius.circular(10.0)); + + final resolvedAllValue = allAttr.resolve(EmptyMixData); + + expect(resolvedAllValue, allValue); + + const horizontalAttr = BorderRadiusAttribute.horizontal( + left: Radius.circular(5.0), + right: Radius.circular(10.0), + ); + + const horizontalValue = BorderRadius.horizontal( + left: Radius.circular(5.0), + right: Radius.circular(10.0), + ); + + final resolvedHorizontalValue = horizontalAttr.resolve(EmptyMixData); + + expect(resolvedHorizontalValue, horizontalValue); + + const verticalAttr = BorderRadiusAttribute.vertical( + top: Radius.circular(5.0), + bottom: Radius.circular(10.0), + ); + + const verticalValue = BorderRadius.vertical( + top: Radius.circular(5.0), + bottom: Radius.circular(10.0), + ); + + final resolvedVerticalValue = verticalAttr.resolve(EmptyMixData); + + expect(resolvedVerticalValue, verticalValue); + + final circularAttr = BorderRadiusAttribute.circular(5.0); + final circularValue = BorderRadius.circular(5.0); + + final resolvedCircularValue = circularAttr.resolve(EmptyMixData); + + expect(resolvedCircularValue, circularValue); + + const onlyAttr = BorderRadiusAttribute( + topLeft: Radius.circular(5.0), + topRight: Radius.circular(10.0), + bottomLeft: Radius.circular(15.0), + bottomRight: Radius.circular(20.0), + ); + + const onlyValue = BorderRadius.only( + topLeft: Radius.circular(5.0), + topRight: Radius.circular(10.0), + bottomLeft: Radius.circular(15.0), + bottomRight: Radius.circular(20.0), + ); + + final resolvedOnlyValue = onlyAttr.resolve(EmptyMixData); + + expect(resolvedOnlyValue, onlyValue); + }); + }); + + group('BorderRadiusDirectionalAttribute', () { + test('BorderRadiusDirectionalAttribute.all', () { + const attr = BorderRadiusDirectionalAttribute.all(Radius.circular(5.0)); + expect(attr.topStart, const Radius.circular(5.0)); + expect(attr.topEnd, const Radius.circular(5.0)); + expect(attr.bottomStart, const Radius.circular(5.0)); + expect(attr.bottomEnd, const Radius.circular(5.0)); + }); + + test('BorderRadiusDirectionalAttribute.horizontal', () { + const attr = BorderRadiusDirectionalAttribute.horizontal( + start: Radius.circular(5.0), + end: Radius.circular(10.0), + ); + + expect(attr.topStart, const Radius.circular(5.0)); + expect(attr.topEnd, const Radius.circular(10.0)); + expect(attr.bottomStart, const Radius.circular(5.0)); + expect(attr.bottomEnd, const Radius.circular(10.0)); + }); + + test('BorderRadiusDirectionalAttribute.vertical', () { + const attr = BorderRadiusDirectionalAttribute.vertical( + top: Radius.circular(5.0), + bottom: Radius.circular(10.0), + ); + + expect(attr.topStart, const Radius.circular(5.0)); + expect(attr.topEnd, const Radius.circular(5.0)); + expect(attr.bottomStart, const Radius.circular(10.0)); + expect(attr.bottomEnd, const Radius.circular(10.0)); + }); + + test('BorderRadiusDirectionalAttribute.circular', () { + final attr = BorderRadiusDirectionalAttribute.circular(5.0); + expect(attr.topStart, const Radius.circular(5.0)); + expect(attr.topEnd, const Radius.circular(5.0)); + expect(attr.bottomStart, const Radius.circular(5.0)); + expect(attr.bottomEnd, const Radius.circular(5.0)); + }); + + test('merge returns merged object correctly', () { + const attr1 = BorderRadiusDirectionalAttribute.horizontal( + start: Radius.circular(5.0), + end: Radius.circular(10.0), + ); + const attr2 = BorderRadiusDirectionalAttribute.vertical( + top: Radius.circular(5.0), + bottom: Radius.circular(10.0), + ); + + final merged = attr1.merge(attr2); + + expect(merged.topStart, attr2.topStart); + expect(merged.topEnd, attr2.topEnd); + expect(merged.bottomStart, attr2.bottomStart); + expect(merged.bottomEnd, attr2.bottomEnd); + }); + + test('merge should combine two BorderRadiusDirectionalAttributes correctly', + () { + const borderRadius1 = + BorderRadiusDirectionalAttribute.all(Radius.circular(10)); + const borderRadius2 = BorderRadiusDirectionalAttribute( + topStart: Radius.circular(20), + ); + + final mergedBorderRadius = borderRadius1.merge(borderRadius2); + + expect(mergedBorderRadius.topStart, const Radius.circular(20)); + expect(mergedBorderRadius.topEnd, const Radius.circular(10)); + expect(mergedBorderRadius.bottomStart, const Radius.circular(10)); + expect(mergedBorderRadius.bottomEnd, const Radius.circular(10)); + }); + + test('resolve should create a BorderRadius with the correct values', () { + const borderRadius = BorderRadiusDirectionalAttribute( + topStart: Radius.circular(10), + topEnd: Radius.circular(20), + bottomStart: Radius.circular(30), + bottomEnd: Radius.circular(40), + ); + + final resolvedBorderRadius = borderRadius.resolve(EmptyMixData); + + expect(resolvedBorderRadius.topStart, const Radius.circular(10)); + expect(resolvedBorderRadius.topEnd, const Radius.circular(20)); + expect(resolvedBorderRadius.bottomStart, const Radius.circular(30)); + expect(resolvedBorderRadius.bottomEnd, const Radius.circular(40)); + }); + + test('Equality holds when properties are the same', () { + const attr1 = BorderRadiusDirectionalAttribute( + topStart: Radius.circular(5.0), + topEnd: Radius.circular(10.0), + bottomStart: Radius.circular(15.0), + bottomEnd: Radius.circular(20.0), + ); + const attr2 = BorderRadiusDirectionalAttribute( + topStart: Radius.circular(5.0), + topEnd: Radius.circular(10.0), + bottomStart: Radius.circular(15.0), + bottomEnd: Radius.circular(20.0), + ); + expect(attr1, attr2); + }); + + test('Equality fails when properties are different', () { + const attr1 = BorderRadiusDirectionalAttribute( + topStart: Radius.circular(5.0), + topEnd: Radius.circular(10.0), + bottomStart: Radius.circular(15.0), + bottomEnd: Radius.circular(20.0), + ); + + const attr2 = BorderRadiusDirectionalAttribute( + topStart: Radius.circular(5.0), + topEnd: Radius.circular(10.0), + bottomStart: Radius.circular(15.0), + bottomEnd: Radius.circular(25.0), + ); + expect(attr1, isNot(attr2)); + }); + + test('Matches BorderRadius contructors', () { + const allAttr = + BorderRadiusDirectionalAttribute.all(Radius.circular(10.0)); + const allValue = BorderRadiusDirectional.all(Radius.circular(10.0)); + + final resolvedAllValue = allAttr.resolve(EmptyMixData); + + expect(resolvedAllValue, allValue); + + const horizontalAttr = BorderRadiusDirectionalAttribute.horizontal( + start: Radius.circular(5.0), + end: Radius.circular(10.0), + ); + + const horizontalValue = BorderRadiusDirectional.horizontal( + start: Radius.circular(5.0), + end: Radius.circular(10.0), + ); + + final resolvedHorizontalValue = horizontalAttr.resolve(EmptyMixData); + + expect(resolvedHorizontalValue, horizontalValue); + + const verticalAttr = BorderRadiusDirectionalAttribute.vertical( + top: Radius.circular(5.0), + bottom: Radius.circular(10.0), + ); + + const verticalValue = BorderRadiusDirectional.vertical( + top: Radius.circular(5.0), + bottom: Radius.circular(10.0), + ); + + final resolvedVerticalValue = verticalAttr.resolve(EmptyMixData); + + expect(resolvedVerticalValue, verticalValue); + + final circularAttr = BorderRadiusDirectionalAttribute.circular(5.0); + final circularValue = BorderRadiusDirectional.circular(5.0); + + final resolvedCircularValue = circularAttr.resolve(EmptyMixData); + + expect(resolvedCircularValue, circularValue); + + const onlyAttr = BorderRadiusDirectionalAttribute( + topStart: Radius.circular(5.0), + topEnd: Radius.circular(10.0), + bottomStart: Radius.circular(15.0), + bottomEnd: Radius.circular(20.0), + ); + + const onlyValue = BorderRadiusDirectional.only( + topStart: Radius.circular(5.0), + topEnd: Radius.circular(10.0), + bottomStart: Radius.circular(15.0), + bottomEnd: Radius.circular(20.0), + ); + + final resolvedOnlyValue = onlyAttr.resolve(EmptyMixData); + + expect(resolvedOnlyValue, onlyValue); + }); + }); + + group('BorderSideAttribute', () { + test('from constructor sets all values correctly', () { + final attr = BorderSideAttribute( + color: Colors.red.toAttribute(), + width: 1.0, + style: BorderStyle.solid); + expect(attr.color?.value, Colors.red); + expect(attr.width, 1.0); + expect(attr.style, BorderStyle.solid); + }); + test('resolve returns correct BorderSide', () { + final attr = BorderSideAttribute( + color: Colors.red.toAttribute(), + width: 1.0, + style: BorderStyle.solid); + final borderSide = attr.resolve(EmptyMixData); + expect(borderSide.color, Colors.red); + expect(borderSide.width, 1.0); + expect(borderSide.style, BorderStyle.solid); + }); + test('Equality holds when all attributes are the same', () { + final attr1 = BorderSideAttribute( + color: Colors.red.toAttribute(), + width: 1.0, + style: BorderStyle.solid); + final attr2 = BorderSideAttribute( + color: Colors.red.toAttribute(), + width: 1.0, + style: BorderStyle.solid); + expect(attr1, attr2); + }); + test('Equality fails when attributes are different', () { + final attr1 = BorderSideAttribute( + color: Colors.red.toAttribute(), + width: 1.0, + style: BorderStyle.solid); + final attr2 = BorderSideAttribute( + color: Colors.blue.toAttribute(), + width: 1.0, + style: BorderStyle.solid); + expect(attr1, isNot(attr2)); + }); + }); +} diff --git a/test/src/attributes/color_attribute_test.dart b/test/src/attributes/color_attribute_test.dart new file mode 100644 index 000000000..9385ea298 --- /dev/null +++ b/test/src/attributes/color_attribute_test.dart @@ -0,0 +1,36 @@ +import 'package:flutter/material.dart'; +import 'package:mix/src/attributes/color_attribute.dart'; + +import '../../helpers/testing_utils.dart'; + +void main() { + const colorList = [ + Colors.red, + Colors.green, + Colors.blue, + Colors.yellow, + Colors.orange, + Colors.purple, + Colors.pink, + Colors.black, + Colors.white, + Colors.grey, + ]; + testScalarAttribute( + 'ColorAttribute', + (value) => ColorAttribute(value), + colorList, + ); + + testScalarAttribute( + 'ImageColorAttribute', + (value) => ImageColorAttribute(value), + colorList, + ); + + testScalarAttribute( + 'IconColorAttribute', + (value) => IconColorAttribute(value), + colorList, + ); +} diff --git a/test/src/attributes/constraints_attribute_test.dart b/test/src/attributes/constraints_attribute_test.dart new file mode 100644 index 000000000..3ab037112 --- /dev/null +++ b/test/src/attributes/constraints_attribute_test.dart @@ -0,0 +1,59 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/src/attributes/constraints_attribute.dart'; + +import '../../helpers/testing_utils.dart'; + +void main() { + group('BoxConstraintsAttribute', () { + test('from constructor sets all values correctly', () { + const constraints = BoxConstraints( + minWidth: 50, + maxWidth: 150, + minHeight: 100, + maxHeight: 200, + ); + final attr = constraints.toAttribute(); + expect(attr.minWidth, 50); + expect(attr.maxWidth, 150); + expect(attr.minHeight, 100); + expect(attr.maxHeight, 200); + }); + test('merge returns merged object correctly', () { + const attr1 = BoxConstraintsAttribute(minWidth: 50, minHeight: 100); + const attr2 = BoxConstraintsAttribute(minWidth: 60, minHeight: 110); + final merged = attr1.merge(attr2); + expect(merged.minWidth, 60); + expect(merged.minHeight, 110); + expect(merged.maxWidth, isNull); + expect(merged.maxHeight, isNull); + }); + test('resolve returns correct BoxConstraints with default values', () { + const attr = BoxConstraintsAttribute(); + final constraints = attr.resolve(EmptyMixData); + expect(constraints.minWidth, 0); + expect(constraints.maxWidth, double.infinity); + expect(constraints.minHeight, 0); + expect(constraints.maxHeight, double.infinity); + }); + test('resolve returns correct BoxConstraints with specific values', () { + const attr = BoxConstraintsAttribute(minWidth: 50, minHeight: 100); + final constraints = attr.resolve(EmptyMixData); + expect(constraints.minWidth, 50); + expect(constraints.maxWidth, double.infinity); + expect(constraints.minHeight, 100); + expect(constraints.maxHeight, double.infinity); + return const Placeholder(); + }); + test('Equality holds when all properties are the same', () { + const attr1 = BoxConstraintsAttribute(minWidth: 50, minHeight: 100); + const attr2 = BoxConstraintsAttribute(minWidth: 50, minHeight: 100); + expect(attr1, attr2); + }); + test('Equality fails when properties are different', () { + const attr1 = BoxConstraintsAttribute(minWidth: 50, minHeight: 100); + const attr2 = BoxConstraintsAttribute(minWidth: 60, minHeight: 100); + expect(attr1, isNot(attr2)); + }); + }); +} diff --git a/test/src/attributes/decoration_attribute_test.dart b/test/src/attributes/decoration_attribute_test.dart new file mode 100644 index 000000000..159c40cf7 --- /dev/null +++ b/test/src/attributes/decoration_attribute_test.dart @@ -0,0 +1,84 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/mix.dart'; + +import '../../helpers/testing_utils.dart'; + +void main() { + const linearGradient = LinearGradient(colors: Colors.accents); + const gradientAttribute = GradientAttribute(linearGradient); + group('BoxDecorationAttribute', () { + test('merge returns merged object correctly', () { + final attr1 = BoxDecorationAttribute(color: Colors.red.toAttribute()); + const attr2 = BoxDecorationAttribute(gradient: gradientAttribute); + final merged = attr1.merge(attr2); + expect(merged.color, attr1.color); + expect(merged.gradient, attr2.gradient); + }); + test('resolve returns correct BoxDecoration with default values', () { + const attr = BoxDecorationAttribute(); + final decoration = attr.resolve(EmptyMixData); + expect(decoration, const BoxDecoration()); + return const Placeholder(); + }); + test('resolve returns correct BoxDecoration with specific values', () { + final attr = BoxDecorationAttribute( + color: Colors.red.toAttribute(), gradient: gradientAttribute); + final decoration = attr.resolve(EmptyMixData); + expect(decoration.color, Colors.red); + expect(decoration.gradient, linearGradient); + return const Placeholder(); + }); + test('Equality holds when all properties are the same', () { + final attr1 = BoxDecorationAttribute(color: Colors.red.toAttribute()); + final attr2 = BoxDecorationAttribute(color: Colors.red.toAttribute()); + expect(attr1, attr2); + }); + test('Equality fails when properties are different', () { + final attr1 = BoxDecorationAttribute(color: Colors.red.toAttribute()); + final attr2 = BoxDecorationAttribute(color: Colors.blue.toAttribute()); + expect(attr1, isNot(attr2)); + }); + }); + + group('ShapeDecorationAttribute', () { + test('merge returns merged object correctly', () { + final attr1 = ShapeDecorationAttribute(color: Colors.red.toAttribute()); + const attr2 = ShapeDecorationAttribute(gradient: gradientAttribute); + final merged = attr1.merge(attr2); + expect(merged.color, attr1.color); + expect(merged.gradient, attr2.gradient); + }); + test('resolve returns correct ShapeDecoration with default values', () { + const shapeDecoration = ShapeDecoration(shape: CircleBorder()); + const attr = ShapeDecorationAttribute(shape: CircleBorder()); + + final decoration = attr.resolve(EmptyMixData); + expect(decoration, shapeDecoration); + }); + test('resolve returns correct ShapeDecoration with specific values', () { + final attr1 = ShapeDecorationAttribute( + gradient: linearGradient.toAttribute(), + ); + + final attr2 = ShapeDecorationAttribute( + color: Colors.red.toAttribute(), + ); + final decoration1 = attr1.resolve(EmptyMixData); + final decoration2 = attr2.resolve(EmptyMixData); + + expect(decoration1.gradient, linearGradient); + expect(decoration2.color, Colors.red); + }); + test('Equality holds when all properties are the same', () { + final attr1 = ShapeDecorationAttribute(color: Colors.red.toAttribute()); + final attr2 = ShapeDecorationAttribute(color: Colors.red.toAttribute()); + expect(attr1, attr2); + }); + test('Equality fails when properties are different', () { + final attr1 = ShapeDecorationAttribute(color: Colors.red.toAttribute()); + final attr2 = ShapeDecorationAttribute(color: Colors.blue.toAttribute()); + expect(attr1, isNot(attr2)); + }); + }); +} diff --git a/test/src/attributes/edge_insets_attribute_test.dart b/test/src/attributes/edge_insets_attribute_test.dart new file mode 100644 index 000000000..118f35386 --- /dev/null +++ b/test/src/attributes/edge_insets_attribute_test.dart @@ -0,0 +1,95 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/src/attributes/edge_insets_attribute.dart'; + +import '../../helpers/testing_utils.dart'; + +void main() { + group('EdgeInsetsAttribute', () { + test('resolves to EdgeInsets.only with correct values', () { + const attribute = EdgeInsetsAttribute( + top: 10, + bottom: 20, + left: 30, + right: 40, + ); + + expect( + attribute.resolve(EmptyMixData), + const EdgeInsets.only( + left: 30, + top: 10, + right: 40, + bottom: 20, + )); + }); + + test('merges correctly with another EdgeInsetsAttribute', () { + const attribute1 = EdgeInsetsAttribute( + top: 10, + bottom: 20, + left: 30, + right: 40, + ); + const attribute2 = EdgeInsetsAttribute( + top: 5, + bottom: 15, + left: 25, + right: 35, + ); + final mergedAttribute = attribute1.merge(attribute2); + expect( + mergedAttribute, + const EdgeInsetsAttribute( + top: 5, + bottom: 15, + left: 25, + right: 35, + )); + }); + }); + + group('EdgeInsetsDirectionalAttribute', () { + test('resolves to EdgeInsetsDirectional.only with correct values', () { + const attribute = EdgeInsetsDirectionalAttribute( + top: 10, + bottom: 20, + start: 30, + end: 40, + ); + + expect( + attribute.resolve(EmptyMixData), + const EdgeInsetsDirectional.only( + start: 30, + top: 10, + end: 40, + bottom: 20, + )); + }); + + test('merges correctly with another EdgeInsetsDirectionalAttribute', () { + const attribute1 = EdgeInsetsDirectionalAttribute( + top: 10, + bottom: 20, + start: 30, + end: 40, + ); + const attribute2 = EdgeInsetsDirectionalAttribute( + top: 5, + bottom: 15, + start: 25, + end: 35, + ); + final mergedAttribute = attribute1.merge(attribute2); + expect( + mergedAttribute, + const EdgeInsetsDirectionalAttribute( + top: 5, + bottom: 15, + start: 25, + end: 35, + )); + }); + }); +} diff --git a/test/src/attributes/scalar_attribute_test.dart b/test/src/attributes/scalar_attribute_test.dart new file mode 100644 index 000000000..607d436a8 --- /dev/null +++ b/test/src/attributes/scalar_attribute_test.dart @@ -0,0 +1,269 @@ +import 'package:flutter/material.dart'; +import 'package:mix/src/attributes/scalar_attribute.dart'; + +import '../../helpers/testing_utils.dart'; + +void main() { + testScalarAttribute( + 'AxisAttribute', + (value) => AxisAttribute(value), + Axis.values, + ); + + testScalarAttribute( + 'MainAxisAlignmentAttribute', + (value) => MainAxisAlignmentAttribute(value), + MainAxisAlignment.values); + + testScalarAttribute( + 'MainAxisSizeAttribute', + (value) => MainAxisSizeAttribute(value), + MainAxisSize.values, + ); + + testScalarAttribute( + 'CrossAxisAlignmentAttribute', + (value) => CrossAxisAlignmentAttribute(value), + CrossAxisAlignment.values, + ); + + testScalarAttribute( + 'VerticalDirectionAttribute', + (value) => VerticalDirectionAttribute(value), + VerticalDirection.values, + ); + + testScalarAttribute( + 'TextBaselineAttribute', + (value) => TextBaselineAttribute(value), + TextBaseline.values, + ); + + testScalarAttribute( + 'ClipAttribute', + (value) => ClipAttribute(value), + Clip.values, + ); + + testScalarAttribute( + 'ImageAlignmentAttribute', (value) => ImageAlignmentAttribute(value), [ + Alignment.topLeft, + Alignment.topCenter, + Alignment.topRight, + Alignment.centerLeft, + Alignment.center, + Alignment.centerRight, + Alignment.bottomLeft, + Alignment.bottomCenter, + Alignment.bottomRight, + ]); + + testScalarAttribute( + 'GradientAttribute', (value) => GradientAttribute(value), [ + const LinearGradient( + colors: [Colors.red, Colors.blue], + ), + const RadialGradient( + colors: [Colors.red, Colors.blue], + ), + const SweepGradient( + colors: [Colors.red, Colors.blue], + ), + ]); + + testScalarAttribute( + 'ImageFitAttribute', + (value) => ImageFitAttribute(value), + BoxFit.values, + ); + + testScalarAttribute( + 'ImageRepeatAttribute', + (value) => ImageRepeatAttribute(value), + ImageRepeat.values, + ); + + testScalarAttribute( + 'SoftWrapAttribute', (value) => SoftWrapAttribute(value), [ + false, + true, + ]); + + testScalarAttribute( + 'TextOverflowAttribute', + (value) => TextOverflowAttribute(value), + TextOverflow.values, + ); + + testScalarAttribute( + 'MaxLinesAttribute', (value) => MaxLinesAttribute(value), [ + 1, + 2, + ]); + + testScalarAttribute( + 'TextWidthBasisAttribute', + (value) => TextWidthBasisAttribute(value), + TextWidthBasis.values, + ); + + testScalarAttribute( + 'TextHeightBehaviorAttribute', + (value) => TextHeightBehaviorAttribute(value), [ + const TextHeightBehavior( + applyHeightToFirstAscent: true, + applyHeightToLastDescent: true, + leadingDistribution: TextLeadingDistribution.even, + ), + const TextHeightBehavior( + applyHeightToFirstAscent: false, + applyHeightToLastDescent: false, + leadingDistribution: TextLeadingDistribution.proportional, + ), + ]); + + testScalarAttribute( + 'TransformAttribute', (value) => TransformAttribute(value), [ + Matrix4.identity(), + Matrix4.rotationZ(0.1), + Matrix4.rotationY(0.2), + ]); + + testScalarAttribute( + 'TransformAlignmentAttribute', + (value) => TransformAlignmentAttribute(value), [ + Alignment.topLeft, + Alignment.topCenter, + Alignment.topRight, + Alignment.centerLeft, + Alignment.center, + Alignment.centerRight, + Alignment.bottomLeft, + Alignment.bottomCenter, + Alignment.bottomRight, + ]); + + testScalarAttribute( + 'BlendModeAttribute', + (value) => BlendModeAttribute(value), + BlendMode.values, + ); + + testScalarAttribute( + 'ImageWidthAttribute', + (value) => ImageWidthAttribute(value), + [ + 1.0, + 2.0, + ], + ); + + testScalarAttribute( + 'ImageHeightAttribute', + (value) => ImageHeightAttribute(value), + [ + 1.0, + 2.0, + ], + ); + + testScalarAttribute( + 'TextAlignAttribute', + (value) => TextAlignAttribute(value), + TextAlign.values, + ); + + testScalarAttribute( + 'TextDirectionAttribute', + (value) => TextDirectionAttribute(value), + TextDirection.values, + ); + +// class IconSizeAttribute extends ScalarAttribute { +// const IconSizeAttribute(super.value); + +// @override +// IconSizeAttribute create(value) => IconSizeAttribute(value); +// } + +// class BoxFitAttribute extends ScalarAttribute { +// const BoxFitAttribute(super.value); + +// @override +// BoxFitAttribute create(value) => BoxFitAttribute(value); +// } + +// class StackFitAttribute extends ScalarAttribute { +// const StackFitAttribute(super.value); + +// @override +// StackFitAttribute create(value) => StackFitAttribute(value); +// } + +// class FlexFitAttribute extends ScalarAttribute { +// const FlexFitAttribute(super.value); + +// @override +// FlexFitAttribute create(value) => FlexFitAttribute(value); +// } + + testScalarAttribute( + 'IconSizeAttribute', + (value) => IconSizeAttribute(value), + [ + 1.0, + 2.0, + ], + ); + + testScalarAttribute( + 'BoxFitAttribute', + (value) => BoxFitAttribute(value), + BoxFit.values, + ); + + testScalarAttribute( + 'StackFitAttribute', + (value) => StackFitAttribute(value), + StackFit.values, + ); + + testScalarAttribute( + 'FlexFitAttribute', + (value) => FlexFitAttribute(value), + FlexFit.values, + ); + + testScalarAttribute( + 'BoxShapeAttribute', + (value) => BoxShapeAttribute(value), + BoxShape.values, + ); + + testScalarAttribute( + 'VisibleAttribute', + (value) => VisibleAttribute(value), + [ + false, + true, + ], + ); + + testScalarAttribute( + 'ImageScaleAttribute', + (value) => ImageScaleAttribute(value), + [ + 1.0, + 2.0, + ], + ); + + testScalarAttribute( + 'TextScaleFactorAttribute', + (value) => TextScaleFactorAttribute(value), + [ + 1.0, + 2.0, + ], + ); +} diff --git a/test/src/attributes/shadow_attribute_test.dart b/test/src/attributes/shadow_attribute_test.dart new file mode 100644 index 000000000..2a444f3df --- /dev/null +++ b/test/src/attributes/shadow_attribute_test.dart @@ -0,0 +1,83 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/src/attributes/color_attribute.dart'; +import 'package:mix/src/attributes/shadow_attribute.dart'; + +import '../../helpers/testing_utils.dart'; + +void main() { + group('ShadowAttribute and BoxShadowAttribute', () { + test('ShadowAttribute correctly resolves attributes', () { + const shadowAttribute = ShadowAttribute( + color: ColorAttribute(Colors.green), + offset: Offset(1, 1), + blurRadius: 2.0, + ); + + final resultShadow = shadowAttribute.resolve(EmptyMixData); + + expect(resultShadow.color, Colors.green); + expect(resultShadow.offset, const Offset(1, 1)); + expect(resultShadow.blurRadius, 2.0); + }); + + test('ShadowAttribute correctly merges attributes', () { + const shadowAttribute1 = ShadowAttribute( + color: ColorAttribute(Colors.green), + offset: Offset(1, 1), + blurRadius: 2.0, + ); + + const shadowAttribute2 = ShadowAttribute( + color: ColorAttribute(Colors.blue), + offset: Offset(2, 2), + blurRadius: 4.0, + ); + + final resultShadow = shadowAttribute1.merge(shadowAttribute2); + + expect(resultShadow.color?.value, Colors.blue); + expect(resultShadow.offset, const Offset(2, 2)); + expect(resultShadow.blurRadius, 4.0); + }); + + test('BoxShadowAttribute correctly resolves attributes', () { + const boxShadowAttribute = BoxShadowAttribute( + color: ColorAttribute(Colors.green), + offset: Offset(1, 1), + blurRadius: 2.0, + spreadRadius: 3.0, + ); + + final resultBoxShadow = boxShadowAttribute.resolve(EmptyMixData); + + expect(resultBoxShadow.color, Colors.green, reason: 'color'); + expect(resultBoxShadow.offset, const Offset(1, 1), reason: 'offset'); + expect(resultBoxShadow.blurRadius, 2.0, reason: 'blurRadius'); + expect(resultBoxShadow.spreadRadius, 3.0, reason: 'spreadRadius'); + }); + + test('BoxShadowAttribute correctly merges attributes', () { + const boxShadowAttribute1 = BoxShadowAttribute( + color: ColorAttribute(Colors.green), + offset: Offset(1, 1), + blurRadius: 2.0, + spreadRadius: 3.0, + ); + + const boxShadowAttribute2 = BoxShadowAttribute( + color: ColorAttribute(Colors.blue), + offset: Offset(2, 2), + blurRadius: 4.0, + spreadRadius: 5.0, + ); + + final resultBoxShadow = boxShadowAttribute1.merge(boxShadowAttribute2); + + expect(resultBoxShadow.color?.value, Colors.blue); + expect(resultBoxShadow.offset, const Offset(2, 2)); + expect(resultBoxShadow.blurRadius, 4.0); + expect(resultBoxShadow.spreadRadius, 5.0); + }); + }); +} diff --git a/test/src/attributes/space_attribute_test.dart b/test/src/attributes/space_attribute_test.dart new file mode 100644 index 000000000..9ca2fafdd --- /dev/null +++ b/test/src/attributes/space_attribute_test.dart @@ -0,0 +1,274 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/src/attributes/space_attribute.dart'; + +import '../../helpers/testing_utils.dart'; + +void main() { + group('PaddingAttribute', () { + // Constructor Tests + test('constructs correctly with all properties', () { + const padding = PaddingAttribute(top: 10, bottom: 5, left: 3, right: 7); + expect(padding.top, 10); + expect(padding.bottom, 5); + expect(padding.left, 3); + expect(padding.right, 7); + }); + + test('constructs correctly with no properties', () { + const padding = PaddingAttribute(); + expect(padding.top, null); + expect(padding.bottom, null); + expect(padding.left, null); + expect(padding.right, null); + }); + + // Merge Function Tests + test('merge function merges correctly', () { + const padding1 = PaddingAttribute(top: 10, bottom: 5); + const padding2 = PaddingAttribute(left: 3, right: 7); + + final merged = padding1.merge(padding2); + + expect(merged.top, 10); + expect(merged.bottom, 5); + expect(merged.left, 3); + expect(merged.right, 7); + }); + + test('merge returns itself if other is null', () { + const padding = PaddingAttribute(top: 10, bottom: 5); + final merged = padding.merge(null); + + expect(merged, equals(padding)); + }); + + // Resolve Function Tests + // Assuming a mock for MixData and its resolver + test('resolve function returns correct EdgeInsets', () { + const padding = PaddingAttribute(top: 10, bottom: 5, left: 3, right: 7); + + final resolvedValue = padding.resolve(EmptyMixData); + + expect(resolvedValue, + equals(const EdgeInsets.only(top: 10, bottom: 5, left: 3, right: 7))); + }); + + // Equality Tests + test('equality holds when properties are the same', () { + const padding1 = PaddingAttribute(top: 10, bottom: 5); + const padding2 = PaddingAttribute(top: 10, bottom: 5); + + expect(padding1, equals(padding2)); + }); + + test('equality fails when properties are different', () { + const padding1 = PaddingAttribute(top: 10, bottom: 5); + const padding2 = PaddingAttribute(top: 5, bottom: 10); + + expect(padding1, isNot(equals(padding2))); + }); + }); + + group('PaddingDirectionalAttribute', () { + // Constructor Tests + test('constructs correctly with all properties', () { + const padding = + PaddingDirectionalAttribute(top: 10, bottom: 5, start: 3, end: 7); + expect(padding.top, 10); + expect(padding.bottom, 5); + expect(padding.start, 3); + expect(padding.end, 7); + }); + + test('constructs correctly with no properties', () { + const padding = PaddingDirectionalAttribute(); + expect(padding.top, null); + expect(padding.bottom, null); + expect(padding.start, null); + expect(padding.end, null); + }); + + // Merge Function Tests + test('merge function merges correctly', () { + const padding1 = PaddingDirectionalAttribute(top: 10, bottom: 5); + const padding2 = PaddingDirectionalAttribute(start: 3, end: 7); + + final merged = padding1.merge(padding2); + + expect(merged.top, 10); + expect(merged.bottom, 5); + expect(merged.start, 3); + expect(merged.end, 7); + }); + + test('merge returns itself if other is null', () { + const padding = PaddingDirectionalAttribute(top: 10, bottom: 5); + final merged = padding.merge(null); + + expect(merged, equals(padding)); + }); + + // Resolve Function Tests + // Assuming a mock for MixData and its resolver + test('resolve function returns correct EdgeInsetsDirectional', () { + const padding = + PaddingDirectionalAttribute(top: 10, bottom: 5, start: 3, end: 7); + + final resolvedValue = padding.resolve(EmptyMixData); + + expect( + resolvedValue, + equals(const EdgeInsetsDirectional.only( + top: 10, bottom: 5, start: 3, end: 7))); + }); + + // Equality Tests + test('equality holds when properties are the same', () { + const padding1 = PaddingDirectionalAttribute(top: 10, bottom: 5); + const padding2 = PaddingDirectionalAttribute(top: 10, bottom: 5); + + expect(padding1, equals(padding2)); + }); + + test('equality fails when properties are different', () { + const padding1 = PaddingDirectionalAttribute(top: 10, bottom: 5); + const padding2 = PaddingDirectionalAttribute(top: 5, bottom: 10); + + expect(padding1, isNot(equals(padding2))); + }); + }); + group('MarginAttribute', () { + // Constructor Tests + test('constructs correctly with all properties', () { + const margin = MarginAttribute(top: 10, bottom: 5, left: 3, right: 7); + expect(margin.top, 10); + expect(margin.bottom, 5); + expect(margin.left, 3); + expect(margin.right, 7); + }); + + test('constructs correctly with no properties', () { + const margin = MarginAttribute(); + expect(margin.top, null); + expect(margin.bottom, null); + expect(margin.left, null); + expect(margin.right, null); + }); + + // Merge Function Tests + test('merge function merges correctly', () { + const margin1 = MarginAttribute(top: 10, bottom: 5); + const margin2 = MarginAttribute(left: 3, right: 7); + + final merged = margin1.merge(margin2); + + expect(merged.top, 10); + expect(merged.bottom, 5); + expect(merged.left, 3); + expect(merged.right, 7); + }); + + test('merge returns itself if other is null', () { + const margin = MarginAttribute(top: 10, bottom: 5); + final merged = margin.merge(null); + + expect(merged, equals(margin)); + }); + + // Resolve Function Tests + // Assuming a mock for MixData and its resolver + test('resolve function returns correct EdgeInsets', () { + const margin = MarginAttribute(top: 10, bottom: 5, left: 3, right: 7); + + final resolvedValue = margin.resolve(EmptyMixData); + + expect(resolvedValue, + equals(const EdgeInsets.only(top: 10, bottom: 5, left: 3, right: 7))); + }); + + // Equality Tests + test('equality holds when properties are the same', () { + const margin1 = MarginAttribute(top: 10, bottom: 5); + const margin2 = MarginAttribute(top: 10, bottom: 5); + + expect(margin1, equals(margin2)); + }); + + test('equality fails when properties are different', () { + const margin1 = MarginAttribute(top: 10, bottom: 5); + const margin2 = MarginAttribute(top: 5, bottom: 10); + + expect(margin1, isNot(equals(margin2))); + }); + }); + + group('MarginDirectionalAttribute', () { + // Constructor Tests + test('constructs correctly with all properties', () { + const margin = + MarginDirectionalAttribute(top: 10, bottom: 5, start: 3, end: 7); + expect(margin.top, 10); + expect(margin.bottom, 5); + expect(margin.start, 3); + expect(margin.end, 7); + }); + + test('constructs correctly with no properties', () { + const margin = MarginDirectionalAttribute(); + expect(margin.top, null); + expect(margin.bottom, null); + expect(margin.start, null); + expect(margin.end, null); + }); + + // Merge Function Tests + test('merge function merges correctly', () { + const margin1 = MarginDirectionalAttribute(top: 10, bottom: 5); + const margin2 = MarginDirectionalAttribute(start: 3, end: 7); + + final merged = margin1.merge(margin2); + + expect(merged.top, 10); + expect(merged.bottom, 5); + expect(merged.start, 3); + expect(merged.end, 7); + }); + + test('merge returns itself if other is null', () { + const margin = MarginDirectionalAttribute(top: 10, bottom: 5); + final merged = margin.merge(null); + + expect(merged, equals(margin)); + }); + + // Resolve Function Tests + // Assuming a mock for MixData and its resolver + test('resolve function returns correct EdgeInsetsDirectional', () { + const margin = + MarginDirectionalAttribute(top: 10, bottom: 5, start: 3, end: 7); + + final resolvedValue = margin.resolve(EmptyMixData); + + expect( + resolvedValue, + equals(const EdgeInsetsDirectional.only( + top: 10, bottom: 5, start: 3, end: 7))); + }); + + // Equality Tests + test('equality holds when properties are the same', () { + const margin1 = MarginDirectionalAttribute(top: 10, bottom: 5); + const margin2 = MarginDirectionalAttribute(top: 10, bottom: 5); + + expect(margin1, equals(margin2)); + }); + + test('equality fails when properties are different', () { + const margin1 = MarginDirectionalAttribute(top: 10, bottom: 5); + const margin2 = MarginDirectionalAttribute(top: 5, bottom: 10); + + expect(margin1, isNot(equals(margin2))); + }); + }); +} diff --git a/test/src/attributes/strut_style_attribute_test.dart b/test/src/attributes/strut_style_attribute_test.dart new file mode 100644 index 000000000..5ff9c79bc --- /dev/null +++ b/test/src/attributes/strut_style_attribute_test.dart @@ -0,0 +1,80 @@ +import 'dart:ui'; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/src/attributes/strut_style_attribute.dart'; + +import '../../helpers/testing_utils.dart'; + +void main() { + group('StrutStyleAttribute', () { + test('from constructor sets all values correctly', () { + const attr = StrutStyleAttribute( + fontFamily: 'Roboto', + fontSize: 24.0, + height: 2.0, + leading: 1.0, + fontWeight: FontWeight.bold, + fontStyle: FontStyle.italic, + forceStrutHeight: true, + ); + + expect(attr.fontFamily, 'Roboto'); + expect(attr.fontSize, 24.0); + expect(attr.height, 2.0); + expect(attr.leading, 1.0); + expect(attr.fontWeight, FontWeight.bold); + expect(attr.fontStyle, FontStyle.italic); + expect(attr.forceStrutHeight, true); + }); + + // Test to check if the merge function returns a merged object correctly + test('merge returns merged object correctly', () { + const attr1 = StrutStyleAttribute(fontFamily: 'Roboto', fontSize: 24.0); + const attr2 = StrutStyleAttribute( + height: 2.0, leading: 1.0, fontWeight: FontWeight.bold); + final merged = attr1.merge(attr2); + + expect(merged.fontFamily, 'Roboto'); + expect(merged.fontSize, 24.0); + expect(merged.height, 2.0); + expect(merged.leading, 1.0); + expect(merged.fontWeight, FontWeight.bold); + }); + + // Test to check if the resolve function returns the correct StrutStyle + test('resolve returns correct StrutStyle', () { + const attr = StrutStyleAttribute( + fontFamily: 'Roboto', + fontSize: 24.0, + height: 2.0, + leading: 1.0, + fontWeight: FontWeight.bold, + fontStyle: FontStyle.italic, + ); + final strutStyle = attr.resolve(EmptyMixData); + + expect(strutStyle.fontFamily, 'Roboto'); + expect(strutStyle.fontSize, 24.0); + expect(strutStyle.height, 2.0); + expect(strutStyle.leading, 1.0); + expect(strutStyle.fontWeight, FontWeight.bold); + expect(strutStyle.fontStyle, FontStyle.italic); + }); + + // Test to check if two StrutStyleAttributes with the same properties are equal + test('Equality holds when all properties are the same', () { + const attr1 = StrutStyleAttribute(fontFamily: 'Roboto', fontSize: 24.0); + const attr2 = StrutStyleAttribute(fontFamily: 'Roboto', fontSize: 24.0); + + expect(attr1, attr2); + }); + + // Test to check if two StrutStyleAttributes with different properties are not equal + test('Equality fails when properties are different', () { + const attr1 = StrutStyleAttribute(fontFamily: 'Roboto', fontSize: 24.0); + const attr2 = StrutStyleAttribute(fontFamily: 'Lato', fontSize: 24.0); + + expect(attr1, isNot(attr2)); + }); + }); +} diff --git a/test/src/attributes/style_mix_attribute_test.dart b/test/src/attributes/style_mix_attribute_test.dart new file mode 100644 index 000000000..35b564f9c --- /dev/null +++ b/test/src/attributes/style_mix_attribute_test.dart @@ -0,0 +1,133 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/src/attributes/style_mix_attribute.dart'; +import 'package:mix/src/factory/style_mix.dart'; + +import '../../helpers/testing_utils.dart'; + +void main() { + group('StyleMixAttribute', () { + test('should create an instance with the provided value', () { + // Arrange + final styleMix = StyleMix( + const MockIntScalarAttribute(1), + const MockIntScalarAttribute(2), + ); + + // Act + final attribute = StyleMixAttribute(styleMix); + + // Assert + expect(attribute, isA()); + expect(attribute.value, equals(styleMix)); + }); + + group('merge', () { + test('should return the same object if other is null', () { + // Arrange + final styleMix = StyleMix(const MockStringScalarAttribute('test')); + final attribute = StyleMixAttribute(styleMix); + + // Act + final mergedAttribute = attribute.merge(null); + + // Assert + expect(mergedAttribute, same(attribute)); + }); + + test('should return a new object with merged values if other is not null', + () { + // Arrange + final styleMix1 = StyleMix( + const MockDoubleScalarAttribute(1.0), + const MockIntScalarAttribute(2), + ); + final styleMix2 = StyleMix(const MockDoubleScalarAttribute(2.0)); + final attribute1 = StyleMixAttribute(styleMix1); + final attribute2 = StyleMixAttribute(styleMix2); + + // Act + final mergedAttribute = attribute1.merge(attribute2); + + // Assert + expect(mergedAttribute, isNot(same(attribute1))); + expect(mergedAttribute.value, equals(styleMix1.merge(styleMix2))); + }); + }); + + test('props should return a list containing the value', () { + // Arrange + final styleMix = StyleMix(); + final attribute = StyleMixAttribute(styleMix); + + // Act + final props = attribute.props; + + // Assert + expect(props, isList); + expect(props, contains(styleMix)); + }); + + test('should contain all attributes after multiple merges', () { + const attr1 = MockIntScalarAttribute(3); + const attr2 = MockIntScalarAttribute(1); + const attr3 = MockIntScalarAttribute(5); + + final styleMix1 = StyleMix(attr1); + final styleMix2 = StyleMix(attr2); + final styleMix3 = StyleMix(attr3); + + final styleAttribute1 = StyleMixAttribute(styleMix1); + final styleAttribute2 = StyleMixAttribute(styleMix2); + final styleAttribute3 = StyleMixAttribute(styleMix3); + + // Act + // Simulate the nested merge as it would occur during construction or setup. + // This assumes StyleMix.merge() not only merges attributes but also merges other StyleMixes. + final mergedAttribute1 = styleAttribute1.merge(styleAttribute2); + final mergedAttribute2 = mergedAttribute1.merge(styleAttribute3); + + final finalStyleMix = mergedAttribute1.merge(mergedAttribute2).value; + + expect(finalStyleMix.values, containsAll([attr1, attr2, attr3])); + + // Does not contain any attributes of type StyleMixAttribute + expect(finalStyleMix.values.whereType(), isEmpty); + }); + + test('should handle nested StyleMixAttributes properly', () { + const attr1 = MockIntScalarAttribute(3); + const attr2 = MockIntScalarAttribute(1); + const attr3 = MockIntScalarAttribute(5); + + final style = StyleMix(attr1, attr2, attr3); + + final styleMix = StyleMix(StyleMixAttribute(style)); + + final level1Attribute = StyleMixAttribute(styleMix); + + final level2Attribute = StyleMixAttribute(StyleMix(level1Attribute)); + + final level3Attribute = StyleMixAttribute(StyleMix(level2Attribute)); + + expect(level1Attribute.value.values, containsAll([attr1, attr2, attr3])); + expect(level2Attribute.value.values, containsAll([attr1, attr2, attr3])); + expect(level3Attribute.value.values, containsAll([attr1, attr2, attr3])); + + expect( + level1Attribute.value.values.whereType(), isEmpty); + + expect( + level2Attribute.value.values.whereType(), isEmpty); + expect( + level3Attribute.value.values.whereType(), isEmpty); + + expect(level1Attribute.value.values.length, 3); + expect(level2Attribute.value.values.length, 3); + expect(level3Attribute.value.values.length, 3); + + expect(styleMix, level1Attribute.value); + expect(styleMix, level2Attribute.value); + expect(styleMix, level3Attribute.value); + }); + }); +} diff --git a/test/src/attributes/text_style_attribute_test.dart b/test/src/attributes/text_style_attribute_test.dart new file mode 100644 index 000000000..c32b41ad8 --- /dev/null +++ b/test/src/attributes/text_style_attribute_test.dart @@ -0,0 +1,103 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/src/attributes/text_style_attribute.dart'; + +import '../../helpers/testing_utils.dart'; + +void main() { + group('TextStyleAttribute', () { + test('from constructor sets all values correctly', () { + final attr = TextStyleAttribute(color: Colors.red.toAttribute()); + expect(attr.color?.value, Colors.red); + }); + test('merge returns merged object correctly', () { + final attr1 = TextStyleAttribute( + color: Colors.red.toAttribute(), + fontSize: 24.0, + decoration: TextDecoration.underline, + decorationColor: Colors.blue.toAttribute(), + decorationStyle: TextDecorationStyle.dashed, + fontWeight: FontWeight.bold, + fontStyle: FontStyle.italic, + letterSpacing: 1.0, + wordSpacing: 2.0, + height: 2.0, + locale: const Locale('en', 'US'), + textBaseline: TextBaseline.ideographic, + ); + + final attr2 = TextStyleAttribute( + color: Colors.blue.toAttribute(), + fontSize: 30.0, + decoration: TextDecoration.lineThrough, + decorationColor: Colors.red.toAttribute(), + decorationStyle: TextDecorationStyle.dotted, + fontWeight: FontWeight.w100, + fontStyle: FontStyle.normal, + letterSpacing: 2.0, + wordSpacing: 3.0, + height: 3.0, + locale: const Locale('en', 'US'), + textBaseline: TextBaseline.alphabetic, + ); + + final merged = attr1.merge(attr2); + + expect(merged.color?.value, Colors.blue); + expect(merged.fontSize, 30.0); + expect(merged.decoration, TextDecoration.lineThrough); + expect(merged.decorationColor?.value, Colors.red); + expect(merged.decorationStyle, TextDecorationStyle.dotted); + expect(merged.fontWeight, FontWeight.w100); + expect(merged.fontStyle, FontStyle.normal); + expect(merged.letterSpacing, 2.0); + expect(merged.wordSpacing, 3.0); + expect(merged.height, 3.0); + expect(merged.locale, const Locale('en', 'US')); + expect(merged.textBaseline, TextBaseline.alphabetic); + }); + test('resolve returns correct TextStyle with specific values', () { + final attr = TextStyleAttribute( + color: Colors.red.toAttribute(), + fontSize: 24.0, + decoration: TextDecoration.underline, + decorationColor: Colors.blue.toAttribute(), + decorationStyle: TextDecorationStyle.dashed, + fontWeight: FontWeight.bold, + fontStyle: FontStyle.italic, + letterSpacing: 1.0, + wordSpacing: 2.0, + height: 2.0, + locale: const Locale('en', 'US'), + textBaseline: TextBaseline.ideographic, + ); + final textStyle = attr.resolve(EmptyMixData); + expect(textStyle.color, Colors.red); + expect(textStyle.fontSize, 24.0); + expect(textStyle.decoration, TextDecoration.underline); + expect(textStyle.decorationColor, Colors.blue); + expect(textStyle.decorationStyle, TextDecorationStyle.dashed); + expect(textStyle.fontWeight, FontWeight.bold); + expect(textStyle.fontStyle, FontStyle.italic); + expect(textStyle.letterSpacing, 1.0); + expect(textStyle.wordSpacing, 2.0); + expect(textStyle.height, 2.0); + expect( + textStyle.locale, + const Locale('en', 'US'), + ); + expect(textStyle.textBaseline, TextBaseline.ideographic); + return const Placeholder(); + }); + test('Equality holds when all attributes are the same', () { + final attr1 = TextStyleAttribute(color: Colors.red.toAttribute()); + final attr2 = TextStyleAttribute(color: Colors.red.toAttribute()); + expect(attr1, attr2); + }); + test('Equality fails when attributes are different', () { + final attr1 = TextStyleAttribute(color: Colors.red.toAttribute()); + final attr2 = TextStyleAttribute(color: Colors.blue.toAttribute()); + expect(attr1, isNot(attr2)); + }); + }); +} diff --git a/test/src/decorators/clip_decorator_test.dart b/test/src/decorators/clip_decorator_test.dart new file mode 100644 index 000000000..f1a9cc6bc --- /dev/null +++ b/test/src/decorators/clip_decorator_test.dart @@ -0,0 +1,362 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/src/decorators/clip_decorator.dart'; + +import '../../helpers/testing_utils.dart'; + +class CustomRectClipper extends CustomClipper { + const CustomRectClipper(); + @override + Rect getClip(Size size) => Rect.fromLTWH(0, 0, size.width, size.height); + + @override + bool shouldReclip(CustomClipper oldClipper) => false; +} + +class CustomRRectClipper extends CustomClipper { + const CustomRRectClipper(); + @override + RRect getClip(Size size) => + RRect.fromLTRBR(0, 0, size.width, size.height, const Radius.circular(10)); + + @override + bool shouldReclip(CustomClipper oldClipper) => false; +} + +void main() { + group('ClipDecoratorData', () { + // equality + test('equality', () { + const decoratorData = ClipDecoratorData( + clipBehavior: Clip.antiAlias, + clipper: null, + ); + const otherDecoratorData = ClipDecoratorData( + clipBehavior: Clip.antiAlias, + clipper: null, + ); + expect(decoratorData, otherDecoratorData); + }); + + test('copyWith', () { + const decoratorData = ClipDecoratorData( + clipBehavior: Clip.antiAlias, + clipper: null, + ); + + final copied = decoratorData.copyWith( + clipBehavior: Clip.hardEdge, + clipper: const CustomRRectClipper(), + ); + + expect(decoratorData, isNotNull); + expect(decoratorData.clipBehavior, Clip.antiAlias); + expect(decoratorData.clipper, isNull); + expect(copied, isNotNull); + expect(copied.clipBehavior, Clip.hardEdge); + expect(copied.clipper, isA()); + }); + + test('lerp', () { + const clipDecorator = ClipDecoratorData( + clipBehavior: Clip.antiAlias, + clipper: null, + ); + const other = ClipDecoratorData( + clipBehavior: Clip.hardEdge, + clipper: CustomRRectClipper(), + ); + + final lerped = clipDecorator.lerp(other, 0.4); + + expect(lerped, isNotNull); + expect(lerped.clipBehavior, Clip.antiAlias); + expect(lerped.clipper, isNull); + }); + }); + + group('ClipRRectDecoratorData', () { + // equality + test('equality', () { + const decoratorData = ClipRRectDecoratorData( + clipBehavior: Clip.antiAlias, + clipper: null, + borderRadius: BorderRadius.zero, + ); + const otherDecoratorData = ClipRRectDecoratorData( + clipBehavior: Clip.antiAlias, + clipper: null, + borderRadius: BorderRadius.zero, + ); + expect(decoratorData, otherDecoratorData); + }); + + test('copyWith', () { + const decoratorData = ClipRRectDecoratorData( + clipBehavior: Clip.antiAlias, + clipper: null, + borderRadius: BorderRadius.zero, + ); + + final copied = decoratorData.copyWith( + clipBehavior: Clip.hardEdge, + clipper: const CustomRRectClipper(), + borderRadius: BorderRadius.circular(10.0), + ); + + expect(decoratorData, isNotNull); + expect(decoratorData.clipBehavior, Clip.antiAlias); + expect(decoratorData.clipper, isNull); + expect(decoratorData.borderRadius, BorderRadius.zero); + expect(copied, isNotNull); + expect(copied.clipBehavior, Clip.hardEdge); + expect(copied.clipper, isA()); + expect(copied.borderRadius, BorderRadius.circular(10.0)); + }); + + test('lerp', () { + const clipDecorator = ClipRRectDecoratorData( + clipBehavior: Clip.antiAlias, + clipper: null, + borderRadius: BorderRadius.zero, + ); + final other = ClipRRectDecoratorData( + clipBehavior: Clip.hardEdge, + clipper: const CustomRRectClipper(), + borderRadius: BorderRadius.circular(10.0), + ); + + final lerped = clipDecorator.lerp(other, 0.4); + + expect(lerped, isNotNull); + expect(lerped.clipBehavior, Clip.antiAlias); + expect(lerped.clipper, isNull); + expect( + lerped.borderRadius, + BorderRadius.lerp( + BorderRadius.zero, + BorderRadius.circular(10.0), + 0.4, + ), + ); + + final lerped2 = clipDecorator.lerp(other, 0.6); + + expect(lerped2, isNotNull); + expect(lerped2.clipBehavior, Clip.hardEdge); + expect(lerped2.clipper, isA()); + expect( + lerped2.borderRadius, + BorderRadius.lerp( + BorderRadius.zero, + BorderRadius.circular(10.0), + 0.6, + ), + ); + }); + }); + group('ClipOvalDecorator', () { + testWidgets( + 'renders', + (WidgetTester tester) async { + // Create a ClipDecorator + const clipDecorator = ClipOvalDecorator(); + + // Build our app and trigger a frame + await tester.pumpWidget( + MaterialApp( + home: clipDecorator.render( + Container(color: Colors.blue), + EmptyMixData, + ), + ), + ); + + final finder = find.byType(ClipOval); + final context = tester.element(finder); + final clipOvalWidget = context.widget as ClipOval; + + // Verify that the ClipOval widget is in the tree + expect(finder, findsOneWidget); + expect(clipOvalWidget, isNotNull); + expect(clipOvalWidget, isA()); + }, + ); + + test('merge', () { + const clipDecorator = ClipOvalDecorator(clipBehavior: Clip.antiAlias); + const other = ClipOvalDecorator(clipper: CustomRectClipper()); + final merged = clipDecorator.merge(other); + expect(merged, isNotNull); + expect(merged.clipBehavior, Clip.antiAlias); + expect(merged.clipper, isA()); + }); + + test('resolve', () { + const clipDecorator = ClipOvalDecorator( + clipBehavior: Clip.hardEdge, clipper: CustomRectClipper()); + final resolved = clipDecorator.resolve(EmptyMixData); + expect(resolved, isNotNull); + expect(resolved.clipBehavior, Clip.hardEdge); + expect(resolved.clipper, isA()); + }); + }); + group('ClipRRectDecorator', () { + testWidgets( + 'renders', + (WidgetTester tester) async { + // Define the radius you want to test + final testRadius = BorderRadius.circular(10.0); + + // Create a ClipDecorator + final clipDecorator = ClipRRectDecorator(borderRadius: testRadius); + + // Build our app and trigger a frame + await tester.pumpWidget( + MaterialApp( + home: clipDecorator.render( + Container(color: Colors.blue), + EmptyMixData, + ), + ), + ); + + final finder = find.byType(ClipRRect); + final context = tester.element(finder); + final clipRRectWidget = context.widget as ClipRRect; + + // Verify that the ClipRRect widget is in the tree and has the correct radius + expect(finder, findsOneWidget); + expect(clipRRectWidget.borderRadius, testRadius); + expect(clipRRectWidget, isA()); + }, + ); + + test('merge', () { + const clipDecorator = ClipRRectDecorator( + clipBehavior: Clip.antiAlias, + borderRadius: BorderRadius.zero, + ); + final other = ClipRRectDecorator( + clipper: const CustomRRectClipper(), + clipBehavior: Clip.hardEdge, + borderRadius: BorderRadius.circular(10.0), + ); + final merged = clipDecorator.merge(other); + expect(merged, isNotNull); + expect(merged.clipBehavior, Clip.hardEdge); + expect(merged.borderRadius, BorderRadius.circular(10.0)); + expect(merged.clipper, isA()); + }); + + test('resolve', () { + final clipDecorator = ClipRRectDecorator( + clipper: const CustomRRectClipper(), + clipBehavior: Clip.hardEdge, + borderRadius: BorderRadius.circular(10.0), + ); + final resolved = clipDecorator.resolve(EmptyMixData); + expect(resolved, isNotNull); + expect(resolved.clipBehavior, Clip.hardEdge); + expect(resolved.borderRadius, BorderRadius.circular(10.0)); + expect(resolved.clipper, isA()); + }); + }); + + group('ClipRectDecorator test', () { + testWidgets( + 'renders', + (WidgetTester tester) async { + // Create a ClipDecorator + const clipDecorator = ClipRectDecorator(); + + // Build our app and trigger a frame + await tester.pumpWidget( + MaterialApp( + home: clipDecorator.render( + Container(color: Colors.blue), + EmptyMixData, + ), + ), + ); + + final finder = find.byType(ClipRect); + final context = tester.element(finder); + final clipRectWidget = context.widget as ClipRect; + + // Verify that the ClipRect widget is in the tree + expect(finder, findsOneWidget); + expect(clipRectWidget, isNotNull); + expect(clipRectWidget, isA()); + }, + ); + + test('merge', () { + const clipDecorator = ClipRectDecorator(clipBehavior: Clip.antiAlias); + const other = ClipRectDecorator(clipper: CustomRectClipper()); + final merged = clipDecorator.merge(other); + expect(merged, isNotNull); + expect(merged.clipBehavior, Clip.antiAlias); + expect(merged.clipper, isA()); + }); + + test('resolve', () { + const clipDecorator = ClipRectDecorator( + clipBehavior: Clip.hardEdge, clipper: CustomRectClipper()); + final resolved = clipDecorator.resolve(EmptyMixData); + expect(resolved, isNotNull); + expect(resolved.clipBehavior, Clip.hardEdge); + expect(resolved.clipper, isA()); + }); + }); + + group('ClipPathDecorator', () { + testWidgets( + 'renders', + (WidgetTester tester) async { + const clipPathDecorator = ClipPathDecorator(clipper: TriangleClipper()); + + await tester.pumpWidget( + MaterialApp( + home: clipPathDecorator.render( + Container(color: Colors.blue), + EmptyMixData, + ), + ), + ); + + final finder = find.byType(ClipPath); + final context = tester.element(finder); + final clipPathWidget = context.widget as ClipPath; + + // Verify that the ClipPath widget is in the tree and has the correct path + expect(finder, findsOneWidget); + expect(clipPathWidget.clipper, isA()); + expect(clipPathWidget, isA()); + }, + ); + + test('merge', () { + const clipPathDecorator = ClipPathDecorator( + clipper: TriangleClipper(), + clipBehavior: Clip.antiAlias, + ); + const other = ClipPathDecorator(clipper: TriangleClipper()); + final merged = clipPathDecorator.merge(other); + expect(merged, isNotNull); + expect(merged.clipBehavior, Clip.antiAlias); + expect(merged.clipper, isA()); + }); + + test('resolve', () { + const clipPathDecorator = ClipPathDecorator( + clipBehavior: Clip.hardEdge, + clipper: TriangleClipper(), + ); + final resolved = clipPathDecorator.resolve(EmptyMixData); + expect(resolved, isNotNull); + expect(resolved.clipBehavior, Clip.hardEdge); + expect(resolved.clipper, isA()); + }); + }); +} diff --git a/test/src/decorators/default_decorators_test.dart b/test/src/decorators/default_decorators_test.dart new file mode 100644 index 000000000..890ea5a8d --- /dev/null +++ b/test/src/decorators/default_decorators_test.dart @@ -0,0 +1,362 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/src/decorators/default_decorators.dart'; + +import '../../helpers/testing_utils.dart'; + +void main() { + group( + 'AspectRatioDecorator Tests', + () { + testWidgets( + 'AspectRatioDecorator applies correct aspect ratio', + (WidgetTester tester) async { + // Define the aspect ratio you want to test + const double testAspectRatio = 2.0; + + // Create an AspectRatioDecorator + const aspectRatioDecorator = AspectRatioDecorator(testAspectRatio); + + // Build our app and trigger a frame + await tester.pumpWidget( + MaterialApp( + home: aspectRatioDecorator.render( + Container(color: Colors.blue), + EmptyMixData, + ), + ), + ); + + final finder = find.byType(AspectRatio); + final context = tester.element(finder); + final aspectRatioWidget = context.widget as AspectRatio; + + // Verify that the AspectRatio widget is in the tree and has the correct aspect ratio + expect(finder, findsOneWidget); + expect(aspectRatioWidget.aspectRatio, testAspectRatio); + }, + ); + + testWidgets( + 'AspectRatioDecorator merge combines aspect ratios correctly', + (WidgetTester tester) async { + // Define two different aspect ratios + const double firstAspectRatio = 2.0; + const double secondAspectRatio = 3.0; + + // Create two AspectRatioDecorators + const aspectRatioDecorator1 = AspectRatioDecorator(firstAspectRatio); + const aspectRatioDecorator2 = AspectRatioDecorator(secondAspectRatio); + + // Merge them + final mergedDecorator = aspectRatioDecorator1.merge( + aspectRatioDecorator2, + ); + + // Build a widget with the merged decorator and trigger a frame + await tester.pumpWidget( + MaterialApp( + home: mergedDecorator.render( + Container(color: Colors.red), + EmptyMixData, + ), + ), + ); + + final finder = find.byType(AspectRatio); + final context = tester.element(finder); + final aspectRatioWidget = context.widget as AspectRatio; + + // Verify that the merged aspect ratio is applied + expect(finder, findsOneWidget); + expect(aspectRatioWidget.aspectRatio, secondAspectRatio); + }, + ); + }, + ); + + group( + 'OpacityDecorator', + () { + testWidgets( + 'OpacityDecorator applies correct opacity', + (WidgetTester tester) async { + // Define the opacity you want to test + const double testOpacity = 0.5; + + // Create an OpacityDecorator + const opacityDecorator = OpacityDecorator(testOpacity); + + // Build our app and trigger a frame + await tester.pumpWidget( + MaterialApp( + home: opacityDecorator.render( + Container(color: Colors.blue), + EmptyMixData, + ), + ), + ); + + final finder = find.byType(Opacity); + final context = tester.element(finder); + final opacityWidget = context.widget as Opacity; + + // Verify that the Opacity widget is in the tree and has the correct opacity + expect(finder, findsOneWidget); + expect(opacityWidget.opacity, testOpacity); + }, + ); + + testWidgets( + 'OpacityDecorator merge combines opacities correctly', + (WidgetTester tester) async { + // Define two different opacities + const double firstOpacity = 0.5; + const double secondOpacity = 0.75; + + // Create two OpacityDecorators + const opacityDecorator1 = OpacityDecorator(firstOpacity); + const opacityDecorator2 = OpacityDecorator(secondOpacity); + + // Merge them + final mergedDecorator = opacityDecorator1.merge(opacityDecorator2); + + // Build a widget with the merged decorator and trigger a frame + await tester.pumpWidget( + MaterialApp( + home: mergedDecorator.render( + Container(color: Colors.red), + EmptyMixData, + ), + ), + ); + + final finder = find.byType(Opacity); + final context = tester.element(finder); + final opacityWidget = context.widget as Opacity; + + // Verify that the merged opacity is applied + expect(finder, findsOneWidget); + expect(opacityWidget.opacity, secondOpacity); + }, + ); + }, + ); + + group( + 'RotateDecorator', + () { + testWidgets( + 'RotateDecorator applies correct rotation', + (WidgetTester tester) async { + // Define the rotation you want to test + const int testRotation = 1; + + // Create a RotateDecorator + const rotateDecorator = RotateDecorator(testRotation); + + // Build our app and trigger a frame + await tester.pumpWidget( + MaterialApp( + home: rotateDecorator.render( + Container(color: Colors.blue), + EmptyMixData, + ), + ), + ); + + final finder = find.byType(RotatedBox); + final context = tester.element(finder); + final rotatedBoxWidget = context.widget as RotatedBox; + + // Verify that the RotatedBox widget is in the tree and has the correct rotation + expect(finder, findsOneWidget); + expect(rotatedBoxWidget.quarterTurns, testRotation); + }, + ); + + testWidgets( + 'RotateDecorator merge combines rotations correctly', + (WidgetTester tester) async { + // Define two different rotations + const int firstRotation = 1; + const int secondRotation = 2; + + // Create two RotateDecorators + const rotateDecorator1 = RotateDecorator(firstRotation); + const rotateDecorator2 = RotateDecorator(secondRotation); + + // Merge them + final mergedDecorator = rotateDecorator1.merge(rotateDecorator2); + + // Build a widget with the merged decorator and trigger a frame + await tester.pumpWidget( + MaterialApp( + home: mergedDecorator.render( + Container(color: Colors.red), + EmptyMixData, + ), + ), + ); + + final finder = find.byType(RotatedBox); + final context = tester.element(finder); + final rotatedBoxWidget = context.widget as RotatedBox; + + // Verify that the merged rotation is applied + expect(finder, findsOneWidget); + expect(rotatedBoxWidget.quarterTurns, secondRotation); + }, + ); + }, + ); + + group( + 'ScaleDecorator', + () { + testWidgets( + 'ScaleDecorator applies correct scale', + (WidgetTester tester) async { + // Define the scale you want to test + const double testScale = 0.5; + + // Create a ScaleDecorator + const scaleDecorator = ScaleDecorator(testScale); + + // Build our app and trigger a frame + await tester.pumpWidget( + MaterialApp( + home: scaleDecorator.render( + Container(color: Colors.blue), + EmptyMixData, + ), + ), + ); + + final finder = find.byType(Transform); + final context = tester.element(finder); + final transformWidget = context.widget as Transform; + + expect(finder, findsOneWidget); + + expect(transformWidget.transform, + Matrix4.diagonal3Values(testScale, testScale, 1.0)); + }, + ); + + testWidgets( + 'ScaleDecorator merge combines scales correctly', + (WidgetTester tester) async { + // Define two different scales + const double firstScale = 0.5; + const double secondScale = 0.75; + + // Create two ScaleDecorators + const scaleDecorator1 = ScaleDecorator(firstScale); + const scaleDecorator2 = ScaleDecorator(secondScale); + + // Merge them + final mergedDecorator = scaleDecorator1.merge(scaleDecorator2); + + // Build a widget with the merged decorator and trigger a frame + await tester.pumpWidget( + MaterialApp( + home: mergedDecorator.render( + Container(color: Colors.red), + EmptyMixData, + ), + ), + ); + + final finder = find.byType(Transform); + final context = tester.element(finder); + final transformWidget = context.widget as Transform; + + // Verify that the merged scale is applied + expect(find.byType(Transform), findsOneWidget); + + expect( + transformWidget.transform, + Matrix4.diagonal3Values(secondScale, secondScale, 1.0), + ); + }, + ); + }, + ); + + group( + 'FlexibleDecorator', + () { + testWidgets( + 'FlexibleDecorator applies correct flex', + (WidgetTester tester) async { + // Define the flex you want to test + const int testFlex = 1; + + // Create a FlexibleDecorator + const flexibleDecorator = FlexibleDecorator(flex: testFlex); + + // Build our app and trigger a frame + await tester.pumpWidget( + MaterialApp( + home: Column( + children: [ + flexibleDecorator.render( + Container(color: Colors.blue), + EmptyMixData, + ), + ], + ), + ), + ); + + final finder = find.byType(Flexible); + final context = tester.element(finder); + final flexibleWidget = context.widget as Flexible; + + // Verify that the Flexible widget is in the tree and has the correct flex + expect(finder, findsOneWidget); + expect(flexibleWidget.flex, testFlex); + }, + ); + + testWidgets( + 'FlexibleDecorator merge combines flexes correctly', + (WidgetTester tester) async { + // Define two different flexes + const int firstFlex = 1; + const int secondFlex = 2; + + // Create two FlexibleDecorators + const flexibleDecorator1 = FlexibleDecorator(flex: firstFlex); + const flexibleDecorator2 = FlexibleDecorator(flex: secondFlex); + + // Merge them + final mergedDecorator = flexibleDecorator1.merge(flexibleDecorator2); + + // Build a widget with the merged decorator and trigger a frame + await tester.pumpWidget( + MaterialApp( + home: Column( + children: [ + mergedDecorator.render( + Container(color: Colors.red), + EmptyMixData, + ), + ], + ), + ), + ); + + final finder = find.byType(Flexible); + final context = tester.element(finder); + final flexibleWidget = context.widget as Flexible; + + // Verify that the merged flex is applied + expect(finder, findsOneWidget); + expect(flexibleWidget.flex, secondFlex); + }, + ); + }, + ); +} diff --git a/test/src/directives/text_directive_test.dart b/test/src/directives/text_directive_test.dart new file mode 100644 index 000000000..d71b6f8d7 --- /dev/null +++ b/test/src/directives/text_directive_test.dart @@ -0,0 +1,91 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/mix.dart'; + +import '../../helpers/testing_utils.dart'; + +void main() { + group('TextDirectiveAttribute', () { + test('merge returns merged object correctly', () { + const attr1 = TextDirectiveAttribute([UppercaseDirective()]); + const attr2 = TextDirectiveAttribute([CapitalizeDirective()]); + final merged = attr1.merge(attr2); + expect(merged.value, + [const UppercaseDirective(), const CapitalizeDirective()]); + }); + test('resolve returns correct TextDirective with default values', () { + const attr = TextDirectiveAttribute([]); + final directive = attr.resolve(EmptyMixData); + expect(directive, []); + }); + test('resolve returns correct TextDirective with specific values', () { + const attr = + TextDirectiveAttribute([UppercaseDirective(), CapitalizeDirective()]); + final directive = attr.resolve(EmptyMixData); + expect( + directive, [const UppercaseDirective(), const CapitalizeDirective()]); + }); + test('Equality holds when all properties are the same', () { + const attr1 = TextDirectiveAttribute([UppercaseDirective()]); + const attr2 = TextDirectiveAttribute([UppercaseDirective()]); + expect(attr1, attr2); + }); + test('Equality fails when properties are different', () { + const attr1 = TextDirectiveAttribute([UppercaseDirective()]); + const attr2 = TextDirectiveAttribute([CapitalizeDirective()]); + expect(attr1, isNot(attr2)); + }); + + group('UppercaseDirective', () { + test('modify returns correct value', () { + const directive = UppercaseDirective(); + final modified = directive.modify('hello'); + expect(modified, 'HELLO'); + }); + }); + + group('CapitalizeDirective', () { + test('modify returns correct value', () { + const directive = CapitalizeDirective(); + final modified = directive.modify('hello'); + expect(modified, 'Hello'); + }); + }); + + group('LowercaseDirective', () { + test('modify returns correct value', () { + const directive = LowercaseDirective(); + final modified = directive.modify('HELLO'); + expect(modified, 'hello'); + }); + }); + + group('SentenceCaseDirective', () { + test('modify returns correct value', () { + const directive = SentenceCaseDirective(); + final modified = directive.modify('hello'); + expect(modified, 'Hello'); + }); + }); + + group('TitleCaseDirective', () { + test('modify returns correct value', () { + const directive = TitleCaseDirective(); + final modified = directive.modify('hello'); + expect(modified, 'Hello'); + }); + }); + + group('TextDirective', () { + test('Equality holds when all properties are the same', () { + const attr1 = TextDirectiveAttribute([UppercaseDirective()]); + const attr2 = TextDirectiveAttribute([UppercaseDirective()]); + expect(attr1, attr2); + }); + test('Equality fails when properties are different', () { + const attr1 = TextDirectiveAttribute([UppercaseDirective()]); + const attr2 = TextDirectiveAttribute([CapitalizeDirective()]); + expect(attr1, isNot(attr2)); + }); + }); + }); +} diff --git a/test/src/factory/mix_provider_data_test.dart b/test/src/factory/mix_provider_data_test.dart new file mode 100644 index 000000000..290dfddb6 --- /dev/null +++ b/test/src/factory/mix_provider_data_test.dart @@ -0,0 +1,93 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/src/core/attributes_map.dart'; +import 'package:mix/src/factory/mix_provider_data.dart'; +import 'package:mix/src/factory/style_mix.dart'; +import 'package:mix/src/theme/mix_theme.dart'; +import 'package:mix/src/variants/context_variant.dart'; + +import '../../helpers/testing_utils.dart'; + +void main() { + final mockVariant = ContextVariant('mock', when: (context) => true); + test('MixData create', () { + final mixData = MixData.create( + MockBuildContext(), + StyleMix( + const MockIntScalarAttribute(1), + const MockStringScalarAttribute('test'), + const MockDoubleScalarAttribute(3.0), + const MockDoubleDecoratorAttribute(0.5), + mockVariant( + const MockDoubleScalarAttribute(2.0), + ), + )); + + // Test that the `MixData` object is created with the correct properties. + expect(mixData, isInstanceOf()); + + // Add any other additional assertions that are specific to your use case. + // If you become able to access properties _attributes and _resolver you would assert: + expect(mixData.attributes, isInstanceOf()); + expect(mixData.resolver, isInstanceOf()); + expect(mixData.attributes.length, 4); + expect(mixData.attributeOfType(), + isInstanceOf()); + expect(mixData.attributeOfType(), + const MockStringScalarAttribute('test')); + expect(mixData.attributeOfType(), + isInstanceOf()); + expect(mixData.attributeOfType(), + const MockDoubleScalarAttribute(2.0)); + + expect(mixData.decoratorOfType(), + isInstanceOf>()); + expect(mixData.attributeOfType(), + const MockDoubleDecoratorAttribute(0.5)); + }); + + test('MixData merge', () { + final mixData = MixData.create( + MockBuildContext(), + StyleMix( + const MockIntScalarAttribute(1), + const MockStringScalarAttribute('test'), + const MockDoubleScalarAttribute(3.0), + const MockDoubleDecoratorAttribute(0.5), + mockVariant( + const MockDoubleScalarAttribute(2.0), + ), + )); + + final mixData2 = MixData.create( + MockBuildContext(), + StyleMix( + const MockDoubleScalarAttribute(5.0), + const MockDoubleDecoratorAttribute(0.6), + mockVariant( + const MockDoubleScalarAttribute(4.0), + ), + )); + + final mergedMixData = mixData.merge(mixData2); + + expect(mergedMixData, isInstanceOf()); + expect(mergedMixData.attributes.length, 4); + expect(mergedMixData.attributeOfType(), + isInstanceOf()); + expect(mergedMixData.attributeOfType(), + isInstanceOf()); + expect(mergedMixData.attributeOfType(), + isInstanceOf()); + expect(mergedMixData.decoratorOfType(), + isInstanceOf>()); + + expect(mergedMixData.attributeOfType(), + const MockIntScalarAttribute(1)); + expect(mergedMixData.attributeOfType(), + const MockStringScalarAttribute('test')); + expect(mergedMixData.attributeOfType(), + const MockDoubleScalarAttribute(4.0)); + expect(mergedMixData.decoratorOfType().first, + const MockDoubleDecoratorAttribute(0.6)); + }); +} diff --git a/test/src/factory/style_mix_test.dart b/test/src/factory/style_mix_test.dart new file mode 100644 index 000000000..83c0e5e02 --- /dev/null +++ b/test/src/factory/style_mix_test.dart @@ -0,0 +1,430 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/mix.dart'; +import 'package:mix/src/variants/multi_variant.dart'; + +import '../../helpers/testing_utils.dart'; + +void main() { + const attribute1 = MockDoubleScalarAttribute(1.0); + const attribute2 = MockIntScalarAttribute(2); + const attribute3 = MockBooleanScalarAttribute(true); + const attribute4 = MockStringScalarAttribute('string1'); + const variantAttr1 = Variant('mock1'); + const variantAttr2 = Variant('mock2'); + group('StyleMix()', () { + test('Initialization with All Null Attributes', () { + final mix = StyleMix(null, null, null, null); + expect(mix.styles.isEmpty, true); + expect(mix.variants.isEmpty, true); + }); + + test('Initialization with Mixed Null and Non-Null Attributes', () { + final mix = StyleMix(null, attribute1, null); + expect(mix.styles.length, 1); + expect(mix.variants.isEmpty, true); + expect(mix.styles[0], attribute1); + }); + + test('Initialization with All Non-Null ScalarAttributes', () { + final mix = StyleMix(attribute1, attribute2); + expect(mix.styles.length, 2); + expect(mix.variants.isEmpty, true); + }); + + test('Initialization with All Non-Null VariantAttributes', () { + final mix = StyleMix(variantAttr1(), variantAttr2()); + expect(mix.variants.length, 2); + expect(mix.styles.isEmpty, true); + }); + + test('Initialization with Mixed Scalar and Variant Attributes', () { + final mix = StyleMix(attribute1, variantAttr1()); + expect(mix.styles.length, 1); + expect(mix.variants.length, 1); + }); + + test('Initialization with many typse of attributes', () { + final mix = StyleMix( + attribute1, + attribute2, + variantAttr1(), + variantAttr2(), + ); + expect(mix.styles.length, 2); + expect(mix.styles.isEmpty, false); + expect(mix.variants.length, 2); + expect(mix.variants.isEmpty, false); + }); + }); + + group('StyleMix.create([]) ', () { + test('Initialization with Empty Array', () { + final mix = StyleMix.create([]); + expect(mix.styles.isEmpty, true); + expect(mix.variants.isEmpty, true); + }); + + test('Initialization with attributes', () { + final attributes = [ + attribute1, + attribute2, + attribute3, + attribute4, + variantAttr1(), + ]; + final mix = StyleMix.create(attributes); + expect(mix.styles.isEmpty, false); + expect(mix.variants.isEmpty, false); + expect(mix.styles.length, 4); + expect(mix.variants.length, 1); + expect(mix.length, 5); + }); + + test('Initialization with invalid attribute triggers assertion', () { + final attributes = [ + attribute1, + attribute2, + attribute3, + attribute4, + const MockInvalidAttribute(), + ]; + expect(() => StyleMix.create(attributes), throwsAssertionError); + }); + }); + + group('StyleMix.combine', () { + test( + 'should return a StyleMix with all non-null StyleMix instances combined', + () { + final style1 = StyleMix(attribute1); // Add attributes as needed + final style2 = StyleMix(attribute2); + final style3 = StyleMix(null, attribute3, + variantAttr1(attribute4)); // Partially null attributes + + final combinedStyle = + StyleMix.combine(style1, style2, style3, null, null, null); + + // Expect that combinedStyle contains all attributes of style1, style2, and style3 + expect(combinedStyle.styles.length, 3); + expect(combinedStyle.variants.length, 1); + expect(combinedStyle.length, 4); + + expect(combinedStyle.values.contains(attribute1), true); + expect(combinedStyle.values.contains(attribute2), true); + expect(combinedStyle.values.contains(attribute3), true); + expect(combinedStyle.values.contains(variantAttr1(attribute4)), true); + }); + + test('should return an empty StyleMix when all instances are null', () { + final combinedStyle = + StyleMix.combine(null, null, null, null, null, null); + + // Expect that combinedStyle is an empty StyleMix instance + expect(combinedStyle.styles.isEmpty, true); + expect(combinedStyle.variants.isEmpty, true); + }); + }); + + group('StyleMix.combineList', () { + test('should return a StyleMix with all instances combined', () { + final styleList = [ + StyleMix(attribute1), + StyleMix(attribute2), + StyleMix(attribute3), + StyleMix(variantAttr1(attribute4)), + ]; + + final combinedStyle = StyleMix.combineList(styleList); + + // Expect that combinedStyle contains all attributes of style1, style2, and style3 + expect(combinedStyle.styles.length, 3); + expect(combinedStyle.variants.length, 1); + expect(combinedStyle.length, 4); + + expect(combinedStyle.values.contains(attribute1), true); + expect(combinedStyle.values.contains(attribute2), true); + expect(combinedStyle.values.contains(attribute3), true); + expect(combinedStyle.values.contains(variantAttr1(attribute4)), true); + }); + + test('should return an empty StyleMix when the list is empty', () { + final combinedStyle = StyleMix.combineList([]); + + // Expect that combinedStyle is an empty StyleMix instance + expect(combinedStyle.isEmpty, true); + expect(combinedStyle.isNotEmpty, false); + expect(combinedStyle.styles.isEmpty, true); + expect(combinedStyle.variants.isEmpty, true); + + expect(combinedStyle.length, 0); + }); + }); + + group('StyleMix.chooser() ', () { + test('Condition is True', () { + const trueAttribute = MockIntScalarAttribute(1); + const falseAttribute = MockDoubleScalarAttribute(2.0); + + final trueStyle = StyleMix(trueAttribute); + final falseStyle = StyleMix(falseAttribute); + + final mix = StyleMix.chooser(true, trueStyle, falseStyle); + + expect(mix.styles.length, 1); + expect(mix.styles[0], trueAttribute); + }); + + test('Condition is False', () { + const trueAttribute = MockIntScalarAttribute(1); + const falseAttribute = MockDoubleScalarAttribute(2.0); + + final trueStyle = StyleMix(trueAttribute); + final falseStyle = StyleMix(falseAttribute); + + final mix = StyleMix.chooser(false, trueStyle, falseStyle); + + expect(mix.styles.length, 1); + expect(mix.styles[0], falseAttribute); + }); + + test('Both ifTrue and ifFalse Are Same', () { + const sameAttribute = MockBooleanScalarAttribute(true); + + final sameStyle = StyleMix(sameAttribute); + final otherStyle = StyleMix(const MockBooleanScalarAttribute(false)); + + final style = StyleMix.chooser(true, sameStyle, otherStyle); + + expect(style.styles.length, 1); + expect(style.styles[0], sameAttribute); + expect(sameStyle, style); + }); + }); + + group('StyleMix.selectVariant', () { + const attr1 = MockDoubleScalarAttribute(1.0); + const attr2 = MockIntScalarAttribute(2); + const attr3 = MockBooleanScalarAttribute(true); + + const variantAttr1 = Variant('variant1'); + + test('with a Matched Variant', () { + final style = StyleMix(attr1, attr2, variantAttr1(attr3)); + final updatedStyle = style.selectVariant(variantAttr1); + + expect(updatedStyle.styles.length, 3); + expect(style.styles.length, 2); + expect(updatedStyle.variants.length, 0); + expect(style.variants.length, 1); + }); + + test('with matching multi variant', () { + final multiVariant = MultiVariant(const [variantAttr1, variantAttr2]); + final style = StyleMix(attr1, attr2, multiVariant(attr3)); + final firstStyle = style.selectVariant(variantAttr1); + final secondStyle = firstStyle.selectVariant(variantAttr2); + final thirdStyle = style.selectVariant(variantAttr1, variantAttr2); + + expect(firstStyle.styles.length, 2); + expect(firstStyle.variants.length, 1); + + expect(secondStyle.styles.length, 3); + expect(secondStyle.variants.length, 0); + + expect(thirdStyle.styles.length, 3); + expect(thirdStyle.variants.length, 0); + + expect(secondStyle, thirdStyle); + }); + + test('with an Unmatched Variant', () { + final style = StyleMix(attr1, attr2); + final updatedStyle = style.selectVariant(variantAttr1); + + expect(updatedStyle, style); + }); + }); + + group('StyleMix.selectVariantList', () { + const attr1 = MockDoubleScalarAttribute(1.0); + const attr2 = MockIntScalarAttribute(2); + const attr3 = MockBooleanScalarAttribute(true); + + const variantAttr1 = Variant('variant1'); + const variantAttr2 = Variant('variant2'); + + test('with Matched Variants', () { + final style = StyleMix(attr1, variantAttr1(attr2), variantAttr2(attr3)); + final updatedStyle = + style.selectVariantList([variantAttr1, variantAttr2]); + + expect(style.styles.length, 1); + expect(style.variants.length, 2); + expect(updatedStyle.styles.length, 3); + expect(updatedStyle.variants.length, 0); + }); + + test('with matching multi variant', () { + final multiVariant = MultiVariant(const [variantAttr1, variantAttr2]); + final style = StyleMix(attr1, attr2, multiVariant(attr3)); + final thirdStyle = style.selectVariantList([variantAttr1, variantAttr2]); + + expect(thirdStyle.styles.length, 3); + expect(thirdStyle.variants.length, 0); + }); + + test('with Unmatched Variants', () { + final mix = StyleMix(attr1); + final updatedMix = mix.selectVariantList([variantAttr1, variantAttr2]); + + expect(updatedMix, mix); + }); + + test('with Empty List', () { + final mix = StyleMix(attr1, attr2); + final updatedMix = mix.selectVariantList([]); + + expect(updatedMix, mix); + }); + }); + + group('StyleMix.pickVariants', () { + const attr1 = MockDoubleScalarAttribute(1.0); + const attr2 = MockIntScalarAttribute(2); + + const stringAttr1 = MockStringScalarAttribute('string1'); + const stringAttr2 = MockStringScalarAttribute('string2'); + const stringAttr3 = MockStringScalarAttribute('string3'); + + const outlinedVariant = Variant('outlined'); + const smallVariant = Variant('small'); + + test('Picks specified Variants and ignores others', () { + final style = StyleMix( + attr1, + attr2, + outlinedVariant( + stringAttr1, + stringAttr2, + ), + smallVariant( + stringAttr3, + ), + ); + final pickedMix = style.pickVariants([outlinedVariant, smallVariant]); + + expect(pickedMix.styles.contains(stringAttr1), isTrue); + expect(pickedMix.styles.contains(stringAttr2), isTrue); + expect(pickedMix.styles.contains(stringAttr3), isTrue); + expect(pickedMix.styles.contains(attr1), isFalse); + expect(pickedMix.styles.contains(attr2), isFalse); + expect(pickedMix.variants.isEmpty, isTrue); + }); + + test('Returns empty StyleMix when no Variants are picked', () { + final style = StyleMix(attr1, attr2); + final pickedMix = style.pickVariants([]); + + expect(pickedMix.styles.isEmpty, isTrue); + expect(pickedMix.variants.isEmpty, isTrue); + }); + + test('Returns empty StyleMix when picked Variants are not present', () { + final style = StyleMix(attr1, attr2); // no variants added here + final pickedMix = style.pickVariants([outlinedVariant, smallVariant]); + + expect(pickedMix.styles.isEmpty, isTrue); + expect(pickedMix.variants.isEmpty, isTrue); + }); + }); + + group('StyleMix hashcode', () { + test('should return different hashcode for same attributes', () { + final style1 = StyleMix(attribute1, attribute2); + final style2 = StyleMix(attribute1, attribute2); + + expect(style1.hashCode, isNot(style2.hashCode)); + }); + + test('should return different hashcode for different attributes', () { + final style1 = StyleMix(attribute1, attribute2); + final style2 = StyleMix(attribute1, attribute3); + + expect(style1.hashCode, isNot(style2.hashCode)); + }); + }); + + group('StyleMix equality', () { + test('should return true for same attributes', () { + final style1 = StyleMix(attribute1, attribute2); + final style2 = StyleMix(attribute1, attribute2); + + expect(style1, style2); + }); + + test('should return false for different attributes', () { + final style1 = StyleMix(attribute1, attribute2); + final style2 = StyleMix(attribute1, attribute3); + + expect(style1, isNot(style2)); + }); + }); + + group('StyleMix variantChooser', () { + const variant1 = Variant('Variant1'); + const variant2 = Variant('Variant2'); + final style = StyleMix( + attribute1, + attribute2, + variant1(attribute3), + variant2(attribute4), + ); + test('variantChooser selects the correct variants based on conditions', () { + const useVariant1 = true; + const useVariant2 = false; + + final updatedStyle = style.variantSwitcher([ + const SwitchCondition(useVariant1, variant1), + const SwitchCondition(useVariant2, variant2) + ]); + + expect(style.styles.length, 2); + expect(style.variants.length, 2); + + expect(updatedStyle.variants.length, 1); + expect(updatedStyle.length, 4); + expect(updatedStyle.values.contains(attribute4), isFalse); + expect(updatedStyle.values.contains(variant2(attribute4)), isTrue); + }); + + test('variantChooser returns the same style when no conditions are met', + () { + const useVariant1 = false; + const useVariant2 = false; + + final updatedStyle = style.variantSwitcher([ + const SwitchCondition(useVariant1, variant1), + const SwitchCondition(useVariant2, variant2) + ]); + + expect(updatedStyle, equals(style)); + }); + + test('Returns both styles when both conditions are true', () { + const useVariant1 = true; + const useVariant2 = true; + + final updatedStyle = style.variantSwitcher([ + const SwitchCondition(useVariant1, variant1), + const SwitchCondition(useVariant2, variant2) + ]); + + expect(updatedStyle.values.contains(attribute4), isTrue, reason: '1'); + expect(updatedStyle.values.contains(attribute3), isTrue, reason: '2'); + expect(updatedStyle.values.contains(variant1(attribute3)), isFalse, + reason: '3'); + expect(updatedStyle.values.contains(variant2(attribute4)), isFalse, + reason: '4'); + }); + }); +} diff --git a/test/src/helpers/deep_collection_equality_test.dart b/test/src/helpers/deep_collection_equality_test.dart new file mode 100644 index 000000000..b984ae96b --- /dev/null +++ b/test/src/helpers/deep_collection_equality_test.dart @@ -0,0 +1,276 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/src/core/equality/deep_collection_equality.dart'; + +void main() { + group('DeepEqualityChecker hash code', () { + const deepEquality = DeepCollectionEquality(); + test('checks primitive type equality', () { + expect(deepEquality.equals(1, 1), isTrue); + expect(deepEquality.equals('string', 'string'), isTrue); + expect(deepEquality.equals(1.0, 1.0), isTrue); + expect(deepEquality.equals(1, '1'), isFalse); + expect(deepEquality.equals('1', 1), isFalse); + expect(deepEquality.equals(1, 2), isFalse); + }); + + test('checks Map equality with simple types', () { + expect(deepEquality.equals({'key': 'value'}, {'key': 'value'}), isTrue); + expect( + deepEquality.equals({'key1': 'value'}, {'key2': 'value'}), isFalse); + expect( + deepEquality.equals({'key': 'value1'}, {'key': 'value2'}), isFalse); + expect(deepEquality.equals({}, {}), isTrue); + expect( + deepEquality + .equals({'key': 'value'}, {'key': 'value', 'extra': 'value'}), + isFalse); + }); + + test('checks Set equality with simple types', () { + expect(deepEquality.equals({1, 2, 3}, {1, 2, 3}), isTrue); + expect(deepEquality.equals({1, 2}, {1, 2, 3}), isFalse); + expect(deepEquality.equals({3, 2, 1}, {1, 2, 3}), + isTrue); // Order should not matter in sets + expect(deepEquality.equals({1}, {1, 1, 1}), + isTrue); // Duplicate elements in a set + }); + + test('checks Iterable equality with simple types', () { + expect(deepEquality.equals([1, 2, 3], [1, 2, 3]), isTrue, reason: '1'); + expect(deepEquality.equals([1, 2, 3], [3, 2, 1]), isFalse, reason: '2'); + expect(deepEquality.equals([], []), isTrue, reason: '3'); + expect(deepEquality.equals([1, 2, 3], [1, 2]), isFalse, reason: '4'); + }); + + test('checks nested collection equality', () { + expect( + deepEquality.equals([ + {'key': 'value'}, + {'key2': 'value2'} + ], [ + {'key': 'value'}, + {'key2': 'value2'} + ]), + isTrue); + expect( + deepEquality.equals({ + 'outer': {'inner': 'value'} + }, { + 'outer': {'inner': 'value'} + }), + isTrue); + expect( + deepEquality.equals({ + 'set': {1, 2, 3} + }, { + 'set': {3, 2, 1} + }), + isTrue); + expect( + deepEquality.equals([ + 1, + [ + 2, + [3, 4] + ] + ], [ + 1, + [ + 2, + [3, 4] + ] + ]), + isTrue); + expect( + deepEquality.equals({ + 'set': {1, 2, 3} + }, { + 'set': {1, 2} + }), + isFalse); + }); + + test('checks custom object equality', () { + final obj1 = CustomObject(id: 1, value: 'Test'); + final obj2 = CustomObject(id: 1, value: 'Test'); + final obj3 = CustomObject(id: 2, value: 'Test'); + + expect(deepEquality.equals(obj1, obj2), isTrue); + expect(deepEquality.equals(obj1, obj3), isFalse); + }); + test('identical primitive values have the same hash code', () { + expect(deepEquality.hash(123), deepEquality.hash(123)); + expect(deepEquality.hash('string'), deepEquality.hash('string')); + expect(deepEquality.hash(true), deepEquality.hash(true)); + }); + + test('lists with the same values produce the same hash code', () { + var list1 = [1, 2, 3]; + var list2 = [1, 2, 3]; + expect(deepEquality.hash(list1), deepEquality.hash(list2)); + }); + + test('sets with the same values produce the same hash code', () { + var set1 = {1, 2, 3}; + var set2 = {3, 2, 1}; + expect(deepEquality.hash(set1), deepEquality.hash(set2)); + }); + + test('maps with the same key-value pairs produce the same hash code', () { + var map1 = {'a': 1, 'b': 2}; + var map2 = {'b': 2, 'a': 1}; + expect(deepEquality.hash(map1), deepEquality.hash(map2)); + }); + + test( + 'nested collections with identical contents produce the same hash code', + () { + var nestedList1 = [ + [1, 2], + {'a': 1} + ]; + var nestedList2 = [ + [1, 2], + {'a': 1} + ]; + expect(deepEquality.hash(nestedList1), deepEquality.hash(nestedList2)); + }); + + test('unordered collections produce consistent hash codes', () { + var iterable1 = {3, 2, 1}; + var iterable2 = {1, 2, 3}; + expect(deepEquality.hash(iterable1), deepEquality.hash(iterable2)); + }); + + test('custom objects with the same properties produce the same hash code', + () { + var object1 = CustomObject(id: 1, value: 'test'); + var object2 = CustomObject(id: 1, value: 'test'); + expect(deepEquality.hash(object1), deepEquality.hash(object2)); + }); + + test('different collections do not produce the same hash code', () { + var list = [1, 2, 3]; + var set = {1, 2, 3}; + // It's possible but highly unlikely that these two will have the same hash code + expect(deepEquality.hash(list), isNot(deepEquality.hash(set))); + }); + + test( + 'collections with null values handled properly in hash code computation', + () { + var listWithNull = [null, 2, 3]; + var listWithoutNull = [1, 2, 3]; + // Should not throw an exception and should not be equal + expect(() => deepEquality.hash(listWithNull), returnsNormally); + expect(deepEquality.hash(listWithNull), + isNot(deepEquality.hash(listWithoutNull))); + }); + + test('hash code computation is efficient for large collections', () { + var largeList = List.generate(100000, (index) => index); + var timeStart = DateTime.now(); + deepEquality.hash(largeList); + var timeEnd = DateTime.now(); + expect( + timeEnd.difference(timeStart), lessThan(const Duration(seconds: 1))); + }); + + test('checks nested custom object equality', () { + final nestedObj1 = AnotherCustomObject( + id: 1, + name: 'Nested', + children: [ + AnotherCustomObject(id: 2, name: 'Child', children: []), + AnotherCustomObject(id: 3, name: 'Child3', children: []), + AnotherCustomObject( + id: 4, + name: 'Child2', + children: [ + AnotherCustomObject(id: 5, name: 'Child3', children: []) + ], + ), + ], + ); + + final nestedObj2 = AnotherCustomObject( + id: 1, + name: 'Nested', + children: [ + AnotherCustomObject(id: 2, name: 'Child', children: []), + AnotherCustomObject(id: 3, name: 'Child3', children: []), + AnotherCustomObject( + id: 4, + name: 'Child2', + children: [ + AnotherCustomObject(id: 5, name: 'Child3', children: []) + ], + ), + ], + ); + + final nestedObjDifferent = AnotherCustomObject( + id: 1, + name: 'Nested', + children: [ + AnotherCustomObject(id: 2, name: 'Child', children: []), + AnotherCustomObject(id: 3, name: 'Child3', children: []), + AnotherCustomObject( + id: 4, + name: 'ChildX', + children: [ + AnotherCustomObject(id: 5, name: 'Child3', children: []) + ], + ), + ], + ); + + expect(deepEquality.equals(nestedObj1, nestedObj2), isTrue); + expect(deepEquality.equals(nestedObj1, nestedObjDifferent), isFalse); + }); + }); +} + +// A dummy custom object class for testing purposes +class CustomObject { + final int id; + final String value; + + CustomObject({required this.id, required this.value}); + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + + return other is CustomObject && other.id == id && other.value == value; + } + + @override + int get hashCode => id.hashCode ^ value.hashCode; +} + +class AnotherCustomObject { + final int id; + final String name; + final List children; + + AnotherCustomObject( + {required this.id, required this.name, this.children = const []}); + + @override + bool operator ==(Object other) => + identical(this, other) || + other is AnotherCustomObject && + runtimeType == other.runtimeType && + id == other.id && + name == other.name && + listEquals(children, other.children); + + @override + int get hashCode => + id.hashCode ^ + name.hashCode ^ + children.fold( + 0, (previousValue, element) => previousValue ^ element.hashCode); +} diff --git a/test/src/helpers/extensions/build_context_ext_test.dart b/test/src/helpers/extensions/build_context_ext_test.dart new file mode 100644 index 000000000..63fef4057 --- /dev/null +++ b/test/src/helpers/extensions/build_context_ext_test.dart @@ -0,0 +1,83 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/mix.dart'; + +// extension BuildContextExt on BuildContext { +// MixData? get mix => Mix.maybeOf(this); + +// /// MEDIA QUERY EXTENSION METHODS + +// /// Directionality of context. +// TextDirection get directionality => Directionality.of(this); + +// /// Orientation of the device. +// Orientation get orientation => MediaQuery.orientationOf(this); + +// /// Screen size. +// Size get screenSize => MediaQuery.sizeOf(this); + +// // Theme Context Extensions. +// Brightness get brightness => Theme.of(this).brightness; + +// /// Theme context helpers. +// ThemeData get theme => Theme.of(this); + +// /// Theme color scheme. +// ColorScheme get colorScheme => theme.colorScheme; + +// /// Theme text theme. +// TextTheme get textTheme => theme.textTheme; + +// /// Mix Theme Data. +// MixThemeData get mixTheme => MixTheme.of(this); + +// /// Check if brightness is Brightness.dark. +// bool get isDarkMode => brightness == Brightness.dark; + +// /// Is device in landscape mode. +// bool get isLandscape => orientation == Orientation.landscape; + +// /// Is device in portrait mode. +// bool get isPortrait => orientation == Orientation.portrait; +// } +// ; + +void main() { + testWidgets('Mock BuildContext extension methods', (tester) async { + tester.view.physicalSize = const Size(400.0, 600.0); + final theme = ThemeData.light(useMaterial3: true); + await tester.pumpWidget( + MaterialApp( + theme: theme, + home: MixTheme( + data: const MixThemeData.empty(), + child: Builder( + builder: (context) { + return Container(); + }, + ), + ), + ), + ); + + final context = tester.element(find.byType(Container)); + + final mix = context.mix; + expect(mix, isNull); + expect(context.directionality, Directionality.of(context)); + expect(context.orientation, MediaQuery.orientationOf(context)); + // expect(context.screenSize, const Size(400.0, 600.0)); + expect(context.brightness, Theme.of(context).brightness); + expect(context.theme, Theme.of(context)); + expect(context.colorScheme, Theme.of(context).colorScheme); + expect(context.textTheme, Theme.of(context).textTheme); + expect(context.mixTheme, const MixThemeData.empty()); + expect(context.isDarkMode, Theme.of(context).brightness == Brightness.dark); + expect(context.isLandscape, + MediaQuery.orientationOf(context) == Orientation.landscape); + expect(context.isPortrait, + MediaQuery.orientationOf(context) == Orientation.portrait); + + addTearDown(tester.view.resetPhysicalSize); + }); +} diff --git a/test/src/helpers/extensions/iterable_ext_test.dart b/test/src/helpers/extensions/iterable_ext_test.dart new file mode 100644 index 000000000..4bf26ba2a --- /dev/null +++ b/test/src/helpers/extensions/iterable_ext_test.dart @@ -0,0 +1,22 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/mix.dart'; + +void main() { + test('Mock Iterable extension methods', () { + final list = [1, 2, 3, 4, 5]; + expect(list.firstMaybeNull, 1); + expect(list.firstWhereOrNull((element) => element == 3), 3); + expect(list.firstWhereOrNull((element) => element == 6), null); + expect(list.sorted(), [1, 2, 3, 4, 5]); + expect(list.sorted((a, b) => b.compareTo(a)), [5, 4, 3, 2, 1]); + }); + + test('Mock Iterable extension methods', () { + final list = []; + expect(list.firstMaybeNull, null); + expect(list.firstWhereOrNull((element) => element == 3), null); + expect(list.firstWhereOrNull((element) => element == 6), null); + expect(list.sorted(), []); + expect(list.sorted((a, b) => b.compareTo(a)), []); + }); +} diff --git a/test/src/helpers/extensions/string_ext_test.dart b/test/src/helpers/extensions/string_ext_test.dart new file mode 100644 index 000000000..52edf2f84 --- /dev/null +++ b/test/src/helpers/extensions/string_ext_test.dart @@ -0,0 +1,150 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/src/helpers/extensions/string_ext.dart'; + +void main() { + group('StringExt', () { + test('words work properly', () { + String input = 'helloWorld'; + + expect(input.words, ['hello', 'World']); + + input = 'hello_world'; + expect(input.words, ['hello', 'world']); + + input = 'hello-world'; + expect(input.words, ['hello', 'world']); + + input = 'hello world'; + expect(input.words, ['hello', 'world']); + + input = 'HelloWorld'; + expect(input.words, ['Hello', 'World']); + + input = 'HELLO_WORLD'; + expect(input.words, ['HELLO', 'WORLD']); + + input = 'HELLO-WORLD'; + expect(input.words, ['HELLO', 'WORLD']); + + input = 'HELLO WORLD'; + expect(input.words, ['HELLO', 'WORLD']); + }); + + test('isUpperCase work properly', () { + String input = 'HELLO'; + expect(input.isUpperCase, true); + + input = 'hello'; + expect(input.isUpperCase, false); + + input = 'Hello'; + expect(input.isUpperCase, false); + }); + + test('isLowerCase work properly', () { + String input = 'hello'; + expect(input.isLowerCase, true); + + input = 'HELLO'; + expect(input.isLowerCase, false); + + input = 'Hello'; + expect(input.isLowerCase, false); + }); + + test('camelCase work properly', () { + String input = 'hello_world'; + expect(input.camelCase, 'helloWorld'); + + input = 'hello-world'; + expect(input.camelCase, 'helloWorld'); + + input = 'Hello World'; + expect(input.camelCase, 'helloWorld'); + }); + + test('pascalCase work properly', () { + String input = 'hello_world'; + expect(input.pascalCase, 'HelloWorld'); + + input = 'hello-world'; + expect(input.pascalCase, 'HelloWorld'); + + input = 'Hello World'; + expect(input.pascalCase, 'HelloWorld'); + }); + + test('capitalize work properly', () { + String input = 'hello'; + expect(input.capitalize, 'Hello'); + + input = 'HELLO'; + expect(input.capitalize, 'Hello'); + + input = 'hello world'; + expect(input.capitalize, 'Hello world'); + }); + + test('constantCase work properly', () { + String input = 'hello_world'; + expect(input.constantCase, 'HELLO_WORLD'); + + input = 'hello-world'; + expect(input.constantCase, 'HELLO_WORLD'); + + input = 'Hello World'; + expect(input.constantCase, 'HELLO_WORLD'); + }); + + test('snakeCase work properly', () { + String input = 'HelloWorld'; + expect(input.snakeCase, 'hello_world'); + + input = 'hello-world'; + expect(input.snakeCase, 'hello_world'); + + input = 'Hello World'; + expect(input.snakeCase, 'hello_world'); + }); + + test('paramCase work properly', () { + String input = 'HelloWorld'; + expect(input.paramCase, 'hello-world'); + + input = 'hello_world'; + expect(input.paramCase, 'hello-world'); + + input = 'Hello World'; + expect(input.paramCase, 'hello-world'); + }); + + test('titleCase work properly', () { + String input = 'HELLO_WORLD'; + expect(input.titleCase, 'Hello World'); + + input = 'hello-world'; + expect(input.titleCase, 'Hello World'); + + input = 'hello world'; + expect(input.titleCase, 'Hello World'); + }); + }); + + group('ListStringExt', () { + test('lowercase work properly', () { + var input = ['HELLO', 'WORLD']; + expect(input.lowercase, ['hello', 'world']); + + input = ['Hello', 'World']; + expect(input.lowercase, ['hello', 'world']); + }); + + test('uppercase work properly', () { + var input = ['hello', 'world']; + expect(input.uppercase, ['HELLO', 'WORLD']); + + input = ['Hello', 'World']; + expect(input.uppercase, ['HELLO', 'WORLD']); + }); + }); +} diff --git a/test/src/helpers/extensions/style_mix_ext_test.dart b/test/src/helpers/extensions/style_mix_ext_test.dart new file mode 100644 index 000000000..93fc00976 --- /dev/null +++ b/test/src/helpers/extensions/style_mix_ext_test.dart @@ -0,0 +1,273 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/mix.dart'; + +void main() { + final keyOne = UniqueKey(); + final keyTwo = UniqueKey(); + final keyThree = UniqueKey(); + testWidgets('StyleMix.container matches StyledContainer(style:StyleMix)', + (tester) async { + final style = StyleMix(boxDecoration(border: border(color: Colors.red))); + + await tester.pumpWidget( + MaterialApp( + home: Column( + children: [ + style.container(child: const SizedBox(), key: keyOne), + StyledContainer( + key: keyTwo, + style: style, + child: const SizedBox(), + ), + StyledContainer( + key: keyThree, + style: StyleMix.empty, + child: const SizedBox(), + ), + ], + ), + ), + ); + + final containerOne = tester.widget(find.byKey(keyOne)); + final containerTwo = tester.widget(find.byKey(keyTwo)); + final containerThree = tester.widget(find.byKey(keyThree)); + + expect(containerOne.style, style); + expect(containerTwo.style, style); + expect(containerThree.style, isNot(style)); + }); + + testWidgets('StyleMix.box matches StyledContainer(style:StyleMix)', + (tester) async { + final style = StyleMix( + boxDecoration( + border: border(color: Colors.red), + ), + ); + + await tester.pumpWidget( + MaterialApp( + home: Column( + children: [ + style.box(child: const SizedBox(), key: keyOne), + StyledContainer( + key: keyTwo, + style: style, + child: const SizedBox(), + ), + StyledContainer( + key: keyThree, + style: StyleMix.empty, + child: const SizedBox(), + ), + ], + ), + ), + ); + + final containerOne = tester.widget(find.byKey(keyOne)); + final containerTwo = tester.widget(find.byKey(keyTwo)); + final containerThree = tester.widget(find.byKey(keyThree)); + + expect(containerOne.style, style, reason: 'containerOne.style'); + expect(containerTwo.style, style, reason: 'containerTwo.style'); + expect(containerThree.style, isNot(style), reason: 'containerThree.style'); + }); + + testWidgets('StyleMix.hbox matches HBox(style:StyleMix)', (tester) async { + final style = StyleMix(boxDecoration(border: border(color: Colors.red))); + + await tester.pumpWidget( + MaterialApp( + home: Column( + children: [ + style.hbox(children: [const SizedBox()], key: keyOne), + HBox( + key: keyTwo, + style: style, + children: const [SizedBox()], + ), + HBox( + key: keyThree, + style: StyleMix.empty, + children: const [SizedBox()], + ), + ], + ), + ), + ); + + final containerOne = tester.widget(find.byKey(keyOne)); + final containerTwo = tester.widget(find.byKey(keyTwo)); + final containerThree = tester.widget(find.byKey(keyThree)); + + expect(containerOne.style, style); + expect(containerTwo.style, style); + expect(containerThree.style, isNot(style)); + }); + + testWidgets('StyleMix.row matches StyledRow(style:StyleMix)', (tester) async { + final style = StyleMix(boxDecoration(border: border(color: Colors.red))); + + await tester.pumpWidget( + MaterialApp( + home: Column( + children: [ + style.row(children: [const SizedBox()], key: keyOne), + StyledRow( + key: keyTwo, + style: style, + children: const [SizedBox()], + ), + StyledRow( + key: keyThree, + style: StyleMix.empty, + children: const [SizedBox()], + ), + ], + ), + ), + ); + + final containerOne = tester.widget(find.byKey(keyOne)); + final containerTwo = tester.widget(find.byKey(keyTwo)); + final containerThree = tester.widget(find.byKey(keyThree)); + + expect(containerOne.style, style); + expect(containerTwo.style, style); + expect(containerThree.style, isNot(style)); + }); + + testWidgets('StyleMix.text matches StyledText(style:StyleMix)', + (tester) async { + final style = StyleMix(textStyle(color: Colors.red)); + + await tester.pumpWidget( + MaterialApp( + home: Column( + children: [ + style.text('text', key: keyOne), + StyledText( + 'text', + key: keyTwo, + style: style, + ), + StyledText( + 'text', + key: keyThree, + style: StyleMix.empty, + ), + ], + ), + ), + ); + + final containerOne = tester.widget(find.byKey(keyOne)); + final containerTwo = tester.widget(find.byKey(keyTwo)); + final containerThree = tester.widget(find.byKey(keyThree)); + + expect(containerOne.style, style); + expect(containerTwo.style, style); + expect(containerThree.style, isNot(style)); + }); + + testWidgets('StyleMix.vbox matches VBox(style:StyleMix)', (tester) async { + final style = StyleMix(boxDecoration(border: border(color: Colors.red))); + + await tester.pumpWidget( + MaterialApp( + home: Column( + children: [ + style.vbox(children: [const SizedBox()], key: keyOne), + VBox( + key: keyTwo, + style: style, + children: const [SizedBox()], + ), + VBox( + key: keyThree, + style: StyleMix.empty, + children: const [SizedBox()], + ), + ], + ), + ), + ); + + final containerOne = tester.widget(find.byKey(keyOne)); + final containerTwo = tester.widget(find.byKey(keyTwo)); + final containerThree = tester.widget(find.byKey(keyThree)); + + expect(containerOne.style, style); + expect(containerTwo.style, style); + expect(containerThree.style, isNot(style)); + }); + + testWidgets('StyleMix.column matches StyledColumn(style:StyleMix)', + (tester) async { + final style = StyleMix(boxDecoration(border: border(color: Colors.red))); + + await tester.pumpWidget( + MaterialApp( + home: Column( + children: [ + style.column(children: [const SizedBox()], key: keyOne), + StyledColumn( + key: keyTwo, + style: style, + children: const [SizedBox()], + ), + StyledColumn( + key: keyThree, + style: StyleMix.empty, + children: const [SizedBox()], + ), + ], + ), + ), + ); + + final containerOne = tester.widget(find.byKey(keyOne)); + final containerTwo = tester.widget(find.byKey(keyTwo)); + final containerThree = tester.widget(find.byKey(keyThree)); + + expect(containerOne.style, style); + expect(containerTwo.style, style); + expect(containerThree.style, isNot(style)); + }); + + testWidgets('StyleMix.icon matches StyledIcon(style:StyleMix)', + (tester) async { + final style = StyleMix(iconColor(Colors.black)); + + await tester.pumpWidget( + MaterialApp( + home: Column( + children: [ + style.icon(Icons.ac_unit, key: keyOne), + StyledIcon( + Icons.ac_unit, + key: keyTwo, + style: style, + ), + StyledIcon( + Icons.ac_unit, + key: keyThree, + style: StyleMix.empty, + ), + ], + ), + ), + ); + + final containerOne = tester.widget(find.byKey(keyOne)); + final containerTwo = tester.widget(find.byKey(keyTwo)); + final containerThree = tester.widget(find.byKey(keyThree)); + + expect(containerOne.style, style); + expect(containerTwo.style, style); + expect(containerThree.style, isNot(style)); + }); +} diff --git a/test/src/helpers/extensions/values_ext_test.dart b/test/src/helpers/extensions/values_ext_test.dart new file mode 100644 index 000000000..893810245 --- /dev/null +++ b/test/src/helpers/extensions/values_ext_test.dart @@ -0,0 +1,338 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import '../../../helpers/testing_utils.dart'; + +void main() { + group('Extensions', () { + test('StrutStyle toAttribute', () { + const strutStyle = StrutStyle( + fontFamily: 'Roboto', + fontFamilyFallback: ['Arial', 'Helvetica'], + fontSize: 14.0, + fontWeight: FontWeight.bold, + fontStyle: FontStyle.italic, + height: 1.2, + leading: 5.0, + forceStrutHeight: true, + ); + + final attribute = strutStyle.toAttribute(); + + expect(attribute.fontFamily, 'Roboto'); + expect(attribute.fontFamilyFallback, ['Arial', 'Helvetica']); + expect(attribute.fontSize, 14.0); + expect(attribute.fontWeight, FontWeight.bold); + expect(attribute.fontStyle, FontStyle.italic); + expect(attribute.height, 1.2); + expect(attribute.leading, 5.0); + expect(attribute.forceStrutHeight, true); + }); + + test('StrutStyle merge', () { + const strutStyle1 = StrutStyle( + fontFamily: 'Roboto', + fontSize: 14.0, + ); + + const strutStyle2 = StrutStyle( + fontFamilyFallback: ['Arial', 'Helvetica'], + fontWeight: FontWeight.bold, + forceStrutHeight: true, + ); + + final mergedStyle = strutStyle1.merge(strutStyle2); + + expect(mergedStyle.fontFamily, 'Roboto'); + expect(mergedStyle.fontFamilyFallback, ['Arial', 'Helvetica']); + expect(mergedStyle.fontSize, 14.0); + expect(mergedStyle.fontWeight, FontWeight.bold); + expect(mergedStyle.forceStrutHeight, true); + }); + + test('TextAlign toAttribute', () { + const align = TextAlign.center; + final attribute = align.toAttribute(); + expect(attribute.value, TextAlign.center); + }); + + test('Gradient toAttribute', () { + const gradient = LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [Colors.red, Colors.blue], + ); + + final attribute = gradient.toAttribute(); + + expect(attribute.value, gradient); + }); + + test('AlignmentGeometry toAttribute', () { + const alignment = Alignment.center; + final attribute = alignment.toAttribute(); + expect(attribute.resolve(EmptyMixData), Alignment.center); + }); + + test('ShapeDecoration toAttribute', () { + final shapeDecoration = ShapeDecoration( + shape: Border.all(), + gradient: const RadialGradient(colors: [Colors.red, Colors.blue]), + shadows: const [BoxShadow(blurRadius: 5.0)], + ); + + final attribute = shapeDecoration.toAttribute(); + + expect(attribute.shape, Border.all()); + expect(attribute.gradient?.value, + const RadialGradient(colors: [Colors.red, Colors.blue])); + expect(attribute.boxShadow?.map((e) => e.resolve(EmptyMixData)), + [const BoxShadow(blurRadius: 5.0)]); + }); + + test('Alignment toAttribute', () { + const alignment = Alignment(0.5, 0.5); + final attribute = alignment.toAttribute(); + expect(attribute.x, 0.5); + expect(attribute.y, 0.5); + }); + + test('AlignmentDirectional toAttribute', () { + const alignmentDirectional = AlignmentDirectional(0.5, 0.5); + final attribute = alignmentDirectional.toAttribute(); + expect(attribute.start, 0.5); + expect(attribute.y, 0.5); + }); + + test('BoxConstraints toAttribute', () { + const boxConstraints = BoxConstraints( + minWidth: 100.0, + maxWidth: 200.0, + minHeight: 150.0, + maxHeight: 250.0, + ); + final attribute = boxConstraints.toAttribute(); + expect(attribute.minWidth, 100.0); + expect(attribute.maxWidth, 200.0); + expect(attribute.minHeight, 150.0); + expect(attribute.maxHeight, 250.0); + }); + + test('MainAxisAlignment toAttribute', () { + const mainAxisAlignment = MainAxisAlignment.center; + final attribute = mainAxisAlignment.toAttribute(); + expect(attribute.value, MainAxisAlignment.center); + }); + + test('CrossAxisAlignment toAttribute', () { + const crossAxisAlignment = CrossAxisAlignment.center; + final attribute = crossAxisAlignment.toAttribute(); + expect(attribute.value, CrossAxisAlignment.center); + }); + + test('MainAxisSize toAttribute', () { + const mainAxisSize = MainAxisSize.max; + final attribute = mainAxisSize.toAttribute(); + expect(attribute.value, MainAxisSize.max); + }); + + test('TextOverflow toAttribute', () { + const textOverflow = TextOverflow.ellipsis; + final attribute = textOverflow.toAttribute(); + expect(attribute.value, TextOverflow.ellipsis); + }); + + test('VerticalDirection toAttribute', () { + const verticalDirection = VerticalDirection.up; + final attribute = verticalDirection.toAttribute(); + expect(attribute.value, VerticalDirection.up); + }); + + test('Clip toAttribute', () { + const clip = Clip.hardEdge; + final attribute = clip.toAttribute(); + expect(attribute.value, Clip.hardEdge); + }); + + test('TextWidthBasis toAttribute', () { + const textWidthBasis = TextWidthBasis.longestLine; + final attribute = textWidthBasis.toAttribute(); + expect(attribute.value, TextWidthBasis.longestLine); + }); + + test('TextHeightBehavior toAttribute', () { + const textHeightBehavior = + TextHeightBehavior(applyHeightToFirstAscent: true); + final attribute = textHeightBehavior.toAttribute(); + expect(attribute.value, + const TextHeightBehavior(applyHeightToFirstAscent: true)); + }); + + test('TextDirection toAttribute', () { + const textDirection = TextDirection.ltr; + final attribute = textDirection.toAttribute(); + expect(attribute.value, TextDirection.ltr); + }); + + test('ImageRepeat toAttribute', () { + const imageRepeat = ImageRepeat.repeat; + final attribute = imageRepeat.toAttribute(); + expect(attribute.value, ImageRepeat.repeat); + }); + + test('Axis toAttribute', () { + const axis = Axis.horizontal; + final attribute = axis.toAttribute(); + expect(attribute.value, Axis.horizontal); + }); + + test('BlendMode toAttribute', () { + const blendMode = BlendMode.srcOver; + final attribute = blendMode.toAttribute(); + expect(attribute.value, BlendMode.srcOver); + }); + + test('BoxFit toAttribute', () { + const boxFit = BoxFit.cover; + final attribute = boxFit.toAttribute(); + expect(attribute.value, BoxFit.cover); + }); + + test('BoxDecoration toAttribute', () { + final boxDecoration = BoxDecoration( + color: Colors.blue, + border: Border.all(), + borderRadius: BorderRadius.circular(10.0), + gradient: const LinearGradient(colors: [Colors.red, Colors.blue]), + boxShadow: const [BoxShadow(blurRadius: 5.0)], + ); + + final attribute = boxDecoration.toAttribute(); + + expect(attribute.color?.value, Colors.blue); + expect(attribute.border?.resolve(EmptyMixData), Border.all()); + expect(attribute.borderRadius?.resolve(EmptyMixData), + BorderRadius.circular(10.0)); + expect(attribute.gradient?.value, + const LinearGradient(colors: [Colors.red, Colors.blue])); + expect( + attribute.boxShadow?.map( + (e) => e.resolve(EmptyMixData), + ), + [const BoxShadow(blurRadius: 5.0)]); + }); + + test('BorderRadiusGeometry toAttribute', () { + const borderRadius = BorderRadius.all(Radius.circular(10.0)); + final attribute = borderRadius.toAttribute(); + expect(attribute.resolve(EmptyMixData), borderRadius); + }); + + test('BorderRadiusDirectional toAttribute', () { + const borderRadiusDirectional = + BorderRadiusDirectional.all(Radius.circular(10.0)); + final attribute = borderRadiusDirectional.toAttribute(); + expect(attribute.resolve(EmptyMixData), borderRadiusDirectional); + }); + + test('BorderRadius toAttribute', () { + const borderRadius = BorderRadius.all(Radius.circular(10.0)); + final attribute = borderRadius.toAttribute(); + expect(attribute.resolve(EmptyMixData), borderRadius); + }); + + test('TextBaseline toAttribute', () { + const textBaseline = TextBaseline.alphabetic; + final attribute = textBaseline.toAttribute(); + expect(attribute.value, TextBaseline.alphabetic); + }); + + test('Matrix4 toAttribute', () { + final matrix4 = Matrix4.identity(); + final attribute = matrix4.toAttribute(); + expect(attribute.value, Matrix4.identity()); + }); + + test('BorderSide toAttribute', () { + const borderSide = BorderSide( + color: Colors.blue, + width: 2.0, + style: BorderStyle.solid, + ); + final attribute = borderSide.toAttribute(); + expect(attribute.color?.resolve(EmptyMixData), Colors.blue); + expect(attribute.width, 2.0); + expect(attribute.style, BorderStyle.solid); + }); + + test('BoxBorder toAttribute', () { + final boxBorder = Border.all( + style: BorderStyle.solid, width: 1.0, color: const Color(0xff000000)); + final attribute = boxBorder.toAttribute(); + expect( + attribute.top?.resolve(EmptyMixData), + const BorderSide( + style: BorderStyle.solid, width: 1.0, color: Color(0xff000000))); + expect( + attribute.bottom?.resolve(EmptyMixData), + const BorderSide( + style: BorderStyle.solid, width: 1.0, color: Color(0xff000000))); + expect( + attribute.left?.resolve(EmptyMixData), + const BorderSide( + style: BorderStyle.solid, width: 1.0, color: Color(0xff000000))); + expect( + attribute.right?.resolve(EmptyMixData), + const BorderSide( + style: BorderStyle.solid, width: 1.0, color: Color(0xff000000))); + }); + + test('Shadow toAttribute', () { + const shadow = BoxShadow(blurRadius: 10.0, color: Colors.black); + final attribute = shadow.toAttribute(); + expect(attribute.blurRadius, 10.0); + expect(attribute.color?.resolve(EmptyMixData), Colors.black); + }); + + test('BoxShadow toAttribute', () { + const boxShadow = BoxShadow(blurRadius: 5.0, color: Colors.grey); + final attribute = boxShadow.toAttribute(); + expect(attribute.blurRadius, 5.0); + expect(attribute.color?.resolve(EmptyMixData), Colors.grey); + }); + + test('TextStyle toAttribute', () { + const textStyle = TextStyle( + color: Colors.black, + fontSize: 16.0, + fontWeight: FontWeight.bold, + ); + final attribute = textStyle.toAttribute(); + expect(attribute.color?.resolve(EmptyMixData), Colors.black); + expect(attribute.fontSize, 16.0); + expect(attribute.fontWeight, FontWeight.bold); + }); + + test('Border toAttribute', () { + const border = Border( + top: BorderSide(color: Colors.red), + bottom: BorderSide(color: Colors.blue)); + final attribute = border.toAttribute(); + expect(attribute.top?.resolve(EmptyMixData), + const BorderSide(color: Colors.red)); + expect(attribute.bottom?.resolve(EmptyMixData), + const BorderSide(color: Colors.blue)); + }); + + test('BorderDirectional toAttribute', () { + const borderDirectional = BorderDirectional( + top: BorderSide(color: Colors.red), + bottom: BorderSide(color: Colors.blue)); + final attribute = borderDirectional.toAttribute(); + expect(attribute.top?.resolve(EmptyMixData), + const BorderSide(color: Colors.red)); + expect(attribute.bottom?.resolve(EmptyMixData), + const BorderSide(color: Colors.blue)); + }); + }); +} diff --git a/test/src/specs/container_spec_test.dart b/test/src/specs/container_spec_test.dart new file mode 100644 index 000000000..3f57c260d --- /dev/null +++ b/test/src/specs/container_spec_test.dart @@ -0,0 +1,112 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/mix.dart'; + +import '../../helpers/testing_utils.dart'; + +void main() { + group('ContainerSpec', () { + test('resolve', () { + final mix = MixData.create( + MockBuildContext(), + StyleMix( + const AlignmentAttribute(x: 0.0, y: 0.0), + const PaddingAttribute(top: 8, bottom: 16), + const MarginAttribute(top: 10.0, bottom: 12.0), + const BoxConstraintsAttribute(maxWidth: 300.0, minHeight: 200.0), + const BoxDecorationAttribute(color: ColorAttribute(Colors.blue)), + TransformAttribute(Matrix4.translationValues(10.0, 10.0, 0.0)), + const ClipAttribute(Clip.antiAlias), + ), + ); + + final spec = ContainerSpec.resolve(mix); + + expect(spec.alignment, Alignment.center); + expect(spec.padding, const EdgeInsets.only(bottom: 16.0, top: 8.0)); + expect(spec.margin, const EdgeInsets.only(top: 10.0, bottom: 12.0)); + expect(spec.constraints, + const BoxConstraints(maxWidth: 300.0, minHeight: 200.0)); + expect(spec.decoration, const BoxDecoration(color: Colors.blue)); + + expect(spec.transform, Matrix4.translationValues(10.0, 10.0, 0.0)); + expect(spec.clipBehavior, Clip.antiAlias); + }); + + test('copyWith', () { + final spec = ContainerSpec( + alignment: Alignment.center, + padding: const EdgeInsets.all(16.0), + margin: const EdgeInsets.only(top: 8.0, bottom: 8.0), + constraints: const BoxConstraints(maxWidth: 300.0, minHeight: 200.0), + decoration: const BoxDecoration(color: Colors.blue), + transform: Matrix4.translationValues(10.0, 10.0, 0.0), + clipBehavior: Clip.antiAlias, + ); + + final copiedSpec = spec.copyWith(width: 250.0, height: 150.0); + + expect(copiedSpec.alignment, Alignment.center); + expect(copiedSpec.padding, const EdgeInsets.all(16.0)); + expect(copiedSpec.margin, const EdgeInsets.only(top: 8.0, bottom: 8.0)); + expect(copiedSpec.constraints, + const BoxConstraints(maxWidth: 300.0, minHeight: 200.0)); + expect(copiedSpec.decoration, const BoxDecoration(color: Colors.blue)); + + expect(copiedSpec.transform, Matrix4.translationValues(10.0, 10.0, 0.0)); + expect(copiedSpec.clipBehavior, Clip.antiAlias); + }); + + test('lerp', () { + final spec1 = ContainerSpec( + alignment: Alignment.topLeft, + padding: const EdgeInsets.all(8.0), + margin: const EdgeInsets.only(top: 4.0), + constraints: const BoxConstraints(maxWidth: 200.0), + decoration: const BoxDecoration(color: Colors.red), + transform: Matrix4.identity(), + clipBehavior: Clip.none, + ); + + final spec2 = ContainerSpec( + alignment: Alignment.bottomRight, + padding: const EdgeInsets.all(16.0), + margin: const EdgeInsets.only(top: 8.0), + constraints: const BoxConstraints(maxWidth: 400.0), + decoration: const BoxDecoration(color: Colors.blue), + transform: Matrix4.rotationZ(0.5), + clipBehavior: Clip.antiAlias, + ); + + const t = 0.5; + final lerpedSpec = spec1.lerp(spec2, t); + + expect(lerpedSpec.alignment, + Alignment.lerp(Alignment.topLeft, Alignment.bottomRight, t)); + expect( + lerpedSpec.padding, + EdgeInsets.lerp( + const EdgeInsets.all(8.0), const EdgeInsets.all(16.0), t)); + expect( + lerpedSpec.margin, + EdgeInsets.lerp(const EdgeInsets.only(top: 4.0), + const EdgeInsets.only(top: 8.0), t)); + expect( + lerpedSpec.constraints, + BoxConstraints.lerp(const BoxConstraints(maxWidth: 200.0), + const BoxConstraints(maxWidth: 400.0), t)); + expect( + lerpedSpec.decoration, + DecorationTween( + begin: const BoxDecoration(color: Colors.red), + end: const BoxDecoration(color: Colors.blue)) + .lerp(t)); + + expect( + lerpedSpec.transform, + Matrix4Tween(begin: Matrix4.identity(), end: Matrix4.rotationZ(0.5)) + .lerp(t)); + expect(lerpedSpec.clipBehavior, t < 0.5 ? Clip.none : Clip.antiAlias); + }); + }); +} diff --git a/test/src/specs/flex_spec_test.dart b/test/src/specs/flex_spec_test.dart new file mode 100644 index 000000000..1e593490b --- /dev/null +++ b/test/src/specs/flex_spec_test.dart @@ -0,0 +1,118 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/mix.dart'; + +import '../../helpers/testing_utils.dart'; + +void main() { + group('FlexSpec', () { + test('resolve', () { + final mix = MixData.create( + MockBuildContext(), + StyleMix( + const CrossAxisAlignmentAttribute(CrossAxisAlignment.center), + const MainAxisAlignmentAttribute(MainAxisAlignment.center), + const MainAxisSizeAttribute(MainAxisSize.min), + const VerticalDirectionAttribute(VerticalDirection.down), + const AxisAttribute(Axis.horizontal), + const TextDirectionAttribute(TextDirection.ltr), + const TextBaselineAttribute(TextBaseline.alphabetic), + const ClipAttribute(Clip.antiAlias), + ), + ); + + final spec = FlexSpec.resolve(mix); + + expect(spec.crossAxisAlignment, CrossAxisAlignment.center); + expect(spec.mainAxisAlignment, MainAxisAlignment.center); + expect(spec.mainAxisSize, MainAxisSize.min); + expect(spec.verticalDirection, VerticalDirection.down); + expect(spec.direction, Axis.horizontal); + expect(spec.textDirection, TextDirection.ltr); + expect(spec.textBaseline, TextBaseline.alphabetic); + expect(spec.clipBehavior, Clip.antiAlias); + }); + + test('copyWith', () { + const spec = FlexSpec( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + verticalDirection: VerticalDirection.down, + direction: Axis.horizontal, + textDirection: TextDirection.ltr, + textBaseline: TextBaseline.alphabetic, + clipBehavior: Clip.antiAlias, + ); + + final copiedSpec = spec.copyWith( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.end, + mainAxisSize: MainAxisSize.max, + verticalDirection: VerticalDirection.up, + direction: Axis.vertical, + textDirection: TextDirection.rtl, + textBaseline: TextBaseline.ideographic, + clipBehavior: Clip.none, + ); + + expect(copiedSpec.crossAxisAlignment, CrossAxisAlignment.start); + expect(copiedSpec.mainAxisAlignment, MainAxisAlignment.end); + expect(copiedSpec.mainAxisSize, MainAxisSize.max); + expect(copiedSpec.verticalDirection, VerticalDirection.up); + expect(copiedSpec.direction, Axis.vertical); + expect(copiedSpec.textDirection, TextDirection.rtl); + expect(copiedSpec.textBaseline, TextBaseline.ideographic); + expect(copiedSpec.clipBehavior, Clip.none); + + expect(copiedSpec, isNot(spec)); + }); + + test('lerp', () { + const spec1 = FlexSpec( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + verticalDirection: VerticalDirection.down, + direction: Axis.horizontal, + textDirection: TextDirection.ltr, + textBaseline: TextBaseline.alphabetic, + clipBehavior: Clip.none, + ); + + const spec2 = FlexSpec( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.end, + mainAxisSize: MainAxisSize.max, + verticalDirection: VerticalDirection.up, + direction: Axis.vertical, + textDirection: TextDirection.rtl, + textBaseline: TextBaseline.ideographic, + clipBehavior: Clip.antiAlias, + ); + + const t = 0.5; + final lerpedSpec = spec1.lerp(spec2, t); + + expect(lerpedSpec.crossAxisAlignment, CrossAxisAlignment.end); + expect( + lerpedSpec.mainAxisAlignment, + MainAxisAlignment.end, + ); + expect( + lerpedSpec.mainAxisSize, + MainAxisSize.max, + ); + expect( + lerpedSpec.verticalDirection, + VerticalDirection.up, + ); + expect(lerpedSpec.direction, Axis.vertical); + expect(lerpedSpec.textDirection, TextDirection.rtl); + expect(lerpedSpec.textBaseline, TextBaseline.ideographic); + expect(lerpedSpec.clipBehavior, Clip.antiAlias); + + expect(lerpedSpec, isNot(spec1)); + }); + }); +} diff --git a/test/src/specs/icon_spec_test.dart b/test/src/specs/icon_spec_test.dart new file mode 100644 index 000000000..0c1952762 --- /dev/null +++ b/test/src/specs/icon_spec_test.dart @@ -0,0 +1,63 @@ +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/mix.dart'; + +import '../../helpers/testing_utils.dart'; + +void main() { + group('IconSpec', () { + test('resolve', () { + final mix = MixData.create( + MockBuildContext(), + StyleMix( + const IconColorAttribute(Colors.red), + const IconSizeAttribute(20.0), + const TextDirectionAttribute(TextDirection.ltr), + ), + ); + + final spec = IconSpec.resolve(mix); + + expect(spec.color, Colors.red); + expect(spec.size, 20.0); + expect(spec.textDirection, TextDirection.ltr); + }); + + test('copyWith', () { + const spec = IconSpec( + color: Colors.red, + size: 20.0, + textDirection: TextDirection.ltr, + ); + + final copiedSpec = spec.copyWith(color: Colors.blue, size: 30.0); + + expect(copiedSpec.color, Colors.blue); + expect(copiedSpec.size, 30.0); + expect(copiedSpec.textDirection, TextDirection.ltr); + }); + + test('lerp', () { + const spec1 = IconSpec( + color: Colors.red, + size: 20.0, + textDirection: TextDirection.ltr, + ); + + const spec2 = IconSpec( + color: Colors.blue, + size: 30.0, + textDirection: TextDirection.rtl, + ); + + const t = 0.5; + final lerpedSpec = spec1.lerp(spec2, t); + + expect(lerpedSpec.color, Color.lerp(Colors.red, Colors.blue, t)); + expect(lerpedSpec.size, lerpDouble(20.0, 30.0, t)); + expect(lerpedSpec.textDirection, TextDirection.rtl); + }); + }); +} diff --git a/test/src/specs/stack_spec_test.dart b/test/src/specs/stack_spec_test.dart new file mode 100644 index 000000000..e67b316db --- /dev/null +++ b/test/src/specs/stack_spec_test.dart @@ -0,0 +1,76 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/mix.dart'; + +import '../../helpers/testing_utils.dart'; + +void main() { + group('StackSpec', () { + test('resolve', () { + final mix = MixData.create( + MockBuildContext(), + StyleMix( + const AlignmentAttribute(x: 0.0, y: 0.0), + const StackFitAttribute(StackFit.expand), + const TextDirectionAttribute(TextDirection.ltr), + const ClipAttribute(Clip.antiAlias), + ), + ); + + final spec = StackSpec.resolve(mix); + + expect(spec.alignment, Alignment.center); + expect(spec.fit, StackFit.expand); + expect(spec.textDirection, TextDirection.ltr); + expect(spec.clipBehavior, Clip.antiAlias); + }); + + test('copyWith', () { + const spec = StackSpec( + alignment: Alignment.center, + fit: StackFit.expand, + textDirection: TextDirection.ltr, + clipBehavior: Clip.antiAlias, + ); + + final copiedSpec = spec.copyWith( + alignment: Alignment.topLeft, + fit: StackFit.loose, + textDirection: TextDirection.rtl, + clipBehavior: Clip.none, + ); + + expect(copiedSpec.alignment, Alignment.topLeft); + expect(copiedSpec.fit, StackFit.loose); + expect(copiedSpec.textDirection, TextDirection.rtl); + expect(copiedSpec.clipBehavior, Clip.none); + }); + + test('lerp', () { + const spec1 = StackSpec( + alignment: Alignment.topLeft, + fit: StackFit.loose, + textDirection: TextDirection.ltr, + clipBehavior: Clip.none, + ); + + const spec2 = StackSpec( + alignment: Alignment.bottomRight, + fit: StackFit.expand, + textDirection: TextDirection.rtl, + clipBehavior: Clip.antiAlias, + ); + + const t = 0.5; + final lerpedSpec = spec1.lerp(spec2, t); + + expect(lerpedSpec.alignment, + Alignment.lerp(Alignment.topLeft, Alignment.bottomRight, t)); + expect(lerpedSpec.fit, StackFit.expand); + expect(lerpedSpec.textDirection, TextDirection.rtl); + expect(lerpedSpec.clipBehavior, Clip.antiAlias); + + expect(lerpedSpec, isNot(spec1)); + }); + }); +} diff --git a/test/src/specs/text_spec_test.dart b/test/src/specs/text_spec_test.dart new file mode 100644 index 000000000..e62335b9d --- /dev/null +++ b/test/src/specs/text_spec_test.dart @@ -0,0 +1,160 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/mix.dart'; + +import '../../helpers/testing_utils.dart'; + +void main() { + group('TextSpec', () { + test('resolve', () { + final mix = MixData.create( + MockBuildContext(), + StyleMix( + const TextOverflowAttribute(TextOverflow.ellipsis), + const StrutStyleAttribute(fontSize: 20.0), + const TextAlignAttribute(TextAlign.center), + const TextScaleFactorAttribute(1.0), + const MaxLinesAttribute(2), + const TextStyleAttribute(color: ColorAttribute(Colors.red)), + const TextWidthBasisAttribute(TextWidthBasis.longestLine), + const TextHeightBehaviorAttribute( + TextHeightBehavior(applyHeightToFirstAscent: true)), + const TextDirectionAttribute(TextDirection.ltr), + const SoftWrapAttribute(true), + const TextDirectiveAttribute([UppercaseDirective()]), + ), + ); + + final spec = TextSpec.resolve(mix); + + expect(spec.overflow, TextOverflow.ellipsis); + expect(spec.strutStyle, const StrutStyle(fontSize: 20.0)); + expect(spec.textAlign, TextAlign.center); + expect(spec.textScaleFactor, 1.0); + expect(spec.maxLines, 2); + expect(spec.style, const TextStyle(color: Colors.red)); + expect(spec.textWidthBasis, TextWidthBasis.longestLine); + expect( + spec.textHeightBehavior, + const TextHeightBehavior( + applyHeightToFirstAscent: true, applyHeightToLastDescent: true)); + expect(spec.textDirection, TextDirection.ltr); + expect(spec.softWrap, true); + expect(spec.directives, [const UppercaseDirective()]); + + expect(spec.applyTextDirectives('hello'), 'HELLO'); + }); + + test('copyWith', () { + const spec = TextSpec( + overflow: TextOverflow.ellipsis, + strutStyle: StrutStyle(fontSize: 20.0), + textAlign: TextAlign.center, + textScaleFactor: 1.0, + maxLines: 2, + style: TextStyle(color: Colors.red), + textWidthBasis: TextWidthBasis.longestLine, + textHeightBehavior: TextHeightBehavior( + applyHeightToFirstAscent: true, applyHeightToLastDescent: true), + textDirection: TextDirection.ltr, + softWrap: true, + directives: [UppercaseDirective()], + ); + + final copiedSpec = spec.copyWith( + overflow: TextOverflow.fade, + strutStyle: const StrutStyle(fontSize: 30.0), + textAlign: TextAlign.start, + textScaleFactor: 2.0, + maxLines: 3, + style: const TextStyle(color: Colors.blue), + textWidthBasis: TextWidthBasis.parent, + textHeightBehavior: const TextHeightBehavior( + applyHeightToFirstAscent: false, applyHeightToLastDescent: false), + textDirection: TextDirection.rtl, + softWrap: false, + directives: [const LowercaseDirective()], + ); + + expect(copiedSpec.overflow, TextOverflow.fade); + expect(copiedSpec.strutStyle, const StrutStyle(fontSize: 30.0)); + expect(copiedSpec.textAlign, TextAlign.start); + expect(copiedSpec.textScaleFactor, 2.0); + expect(copiedSpec.maxLines, 3); + expect(copiedSpec.style, const TextStyle(color: Colors.blue)); + expect(copiedSpec.textWidthBasis, TextWidthBasis.parent); + expect( + copiedSpec.textHeightBehavior, + const TextHeightBehavior( + applyHeightToFirstAscent: false, + applyHeightToLastDescent: false)); + + expect(copiedSpec.textDirection, TextDirection.rtl); + expect(copiedSpec.softWrap, false); + expect(copiedSpec.directives, [const LowercaseDirective()]); + }); + + test('lerp', () { + const spec1 = TextSpec( + overflow: TextOverflow.ellipsis, + strutStyle: StrutStyle(fontSize: 20.0), + textAlign: TextAlign.center, + textScaleFactor: 1.0, + maxLines: 2, + style: TextStyle(color: Colors.red), + textWidthBasis: TextWidthBasis.longestLine, + textHeightBehavior: TextHeightBehavior( + applyHeightToFirstAscent: true, + applyHeightToLastDescent: true, + ), + textDirection: TextDirection.ltr, + softWrap: true, + directives: [UppercaseDirective()], + ); + + const spec2 = TextSpec( + overflow: TextOverflow.fade, + strutStyle: StrutStyle(fontSize: 30.0), + textAlign: TextAlign.start, + textScaleFactor: 2.0, + maxLines: 3, + style: TextStyle(color: Colors.blue), + textWidthBasis: TextWidthBasis.parent, + textHeightBehavior: TextHeightBehavior( + applyHeightToFirstAscent: false, + applyHeightToLastDescent: false, + ), + textDirection: TextDirection.rtl, + softWrap: false, + directives: [LowercaseDirective()], + ); + + const t = 0.5; + + final lerpedSpec = spec1.lerp(spec2, t); + + expect(lerpedSpec.overflow, TextOverflow.fade); + expect(lerpedSpec.strutStyle, const StrutStyle(fontSize: 30.0)); + expect(lerpedSpec.textAlign, TextAlign.start); + expect(lerpedSpec.textScaleFactor, 1.5); + expect(lerpedSpec.maxLines, 3); + expect( + lerpedSpec.style, + TextStyle.lerp(const TextStyle(color: Colors.red), + const TextStyle(color: Colors.blue), t)); + expect(lerpedSpec.textWidthBasis, TextWidthBasis.parent); + + expect( + lerpedSpec.textHeightBehavior, + const TextHeightBehavior( + applyHeightToFirstAscent: false, + applyHeightToLastDescent: false, + )); + expect(lerpedSpec.textDirection, TextDirection.rtl); + expect(lerpedSpec.softWrap, false); + expect(lerpedSpec.directives, [const LowercaseDirective()]); + + expect(lerpedSpec, isNot(spec1)); + }); + }); +} diff --git a/test/src/theme/tokens/breakpoints_test.dart b/test/src/theme/tokens/breakpoints_test.dart new file mode 100644 index 000000000..a39f81f5a --- /dev/null +++ b/test/src/theme/tokens/breakpoints_test.dart @@ -0,0 +1,90 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/mix.dart'; + +import '../../../helpers/testing_utils.dart'; + +void main() { + test('MixBreakpointsTokens', () { + final breakpoints = MixThemeData().breakpoints; + final context = MockBuildContext(); + final large = breakpoints[BreakpointToken.large]!(context); + final medium = breakpoints[BreakpointToken.medium]!(context); + final small = breakpoints[BreakpointToken.small]!(context); + final xsmall = breakpoints[BreakpointToken.xsmall]!(context); + + expect( + large, + const BreakpointConstraint(minWidth: 1440, maxWidth: double.infinity), + ); + expect( + medium, + const BreakpointConstraint(minWidth: 1024, maxWidth: 1439), + ); + expect( + small, + const BreakpointConstraint(minWidth: 600, maxWidth: 1023), + ); + expect( + xsmall, + const BreakpointConstraint(minWidth: 0, maxWidth: 599), + ); + }); + + test('MixBreakpointsTokens large matches correctly', () { + final breakpoints = MixThemeData().breakpoints; + final context = MockBuildContext(); + final large = breakpoints[BreakpointToken.large]!(context); + + expect( + large.matches(const Size(1440, 1024)), + true, + ); + + expect( + large.matches(const Size(1439, 1024)), + false, + ); + }); + + test('Test orientation for Breakpoint tokens', () { + const portraitBreakpoint = BreakpointToken('--custom-breakpoint'); + const landscapeBreakpoint = BreakpointToken('--another-breakpoint'); + final breakpoints = MixThemeData( + breakpoints: { + portraitBreakpoint: (context) => const BreakpointConstraint( + orientation: BreakpointOrientation.portrait, + ), + landscapeBreakpoint: (context) => const BreakpointConstraint( + orientation: BreakpointOrientation.landscape, + ) + }, + ).breakpoints; + final context = MockBuildContext(); + final portrait = breakpoints[portraitBreakpoint]!(context); + final landscape = breakpoints[landscapeBreakpoint]!(context); + + const portraitSize = Size(2000, 3000); + const landscapeSize = Size(3000, 2000); + + expect( + portrait.matches(portraitSize), + true, + ); + + expect( + landscape.matches(portraitSize), + false, + ); + + expect( + portrait.matches(landscapeSize), + false, + ); + + expect( + landscape.matches(landscapeSize), + true, + ); + }); +} diff --git a/test/src/theme/tokens/color_token_test.dart b/test/src/theme/tokens/color_token_test.dart new file mode 100644 index 000000000..e8a8f39b9 --- /dev/null +++ b/test/src/theme/tokens/color_token_test.dart @@ -0,0 +1,104 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/mix.dart'; +import 'package:mix/src/theme/tokens/color_token.dart'; + +import '../../../helpers/testing_utils.dart'; + +void main() { + group('ColorToken Tests', () { + // Constructor Test + test('Constructor assigns name correctly', () { + const colorToken = ColorToken('testName'); + expect(colorToken.name, 'testName'); + }); + + // Equality Operator Test + test('Equality operator works correctly', () { + const colorToken1 = ColorToken('testName'); + const colorToken2 = ColorToken('testName'); + const colorToken3 = ColorToken('differentName'); + + expect(colorToken1 == colorToken2, isTrue); + expect(colorToken1 == colorToken3, isFalse); + expect(colorToken1 == Object(), isFalse); + }); + + // HashCode Test + test('hashCode is consistent with name', () { + const colorToken1 = ColorToken('testName'); + const colorToken2 = ColorToken('testName'); + const colorToken3 = ColorToken('differentName'); + + expect(colorToken1.hashCode, colorToken2.hashCode); + expect(colorToken1.hashCode, isNot(colorToken3.hashCode)); + }); + + testWidgets('Test it resolves correctly', (tester) async { + const redcolorToken = ColorToken('red'); + const greencolorToken = ColorToken('green'); + const bluecolorToken = ColorToken('blue'); + final theme = MixThemeData(colors: { + redcolorToken: (_) => Colors.red, + greencolorToken: (_) => Colors.green, + bluecolorToken: (_) => Colors.blue, + }); + + await tester.pumpWidget(createWithMixTheme(theme)); + + final context = tester.element(find.byType(Container)); + + final mixData = MixData.create(context, StyleMix.empty); + + expect(mixData.resolver.colorToken(redcolorToken), Colors.red); + expect(mixData.resolver.colorToken(greencolorToken), Colors.green); + expect(mixData.resolver.colorToken(bluecolorToken), Colors.blue); + }); + }); + + group('ColorResolvableToken', () { + test('Constructor assigns name correctly', () { + final colorToken = ColorTokenResolver('testName', (_) => Colors.red); + expect(colorToken.name, 'testName'); + }); + + // Equality Operator Test + test('Equality operator works correctly', () { + final colorToken1 = ColorTokenResolver('testName', (_) => Colors.red); + final colorToken2 = ColorTokenResolver('testName', (_) => Colors.red); + final colorToken3 = + ColorTokenResolver('differentName', (_) => Colors.red); + + expect(colorToken1 == colorToken2, isTrue); + expect(colorToken1 == colorToken3, isFalse); + expect(colorToken1 == Object(), isFalse); + }); + + // HashCode Test + test('hashCode is consistent with name', () { + final colorToken1 = ColorTokenResolver('testName', (_) => Colors.red); + final colorToken2 = ColorTokenResolver('testName', (_) => Colors.red); + final colorToken3 = + ColorTokenResolver('differentName', (_) => Colors.red); + + expect(colorToken1.hashCode, colorToken2.hashCode); + expect(colorToken1.hashCode, isNot(colorToken3.hashCode)); + }); + + testWidgets('Test it resolves correctly', (tester) async { + final redcolorToken = ColorTokenResolver('red', (_) => Colors.red); + final greencolorToken = ColorTokenResolver('green', (_) => Colors.green); + final bluecolorToken = ColorTokenResolver('blue', (_) => Colors.blue); + + await tester.pumpMaterialApp(Container()); + + final context = tester.element(find.byType(Container)); + + final mixData = MixData.create(context, StyleMix.empty); + + expect(mixData.resolver.colorToken(redcolorToken), Colors.red); + expect(mixData.resolver.colorToken(greencolorToken), Colors.green); + expect(mixData.resolver.colorToken(bluecolorToken), Colors.blue); + }); + }); +} diff --git a/test/src/theme/tokens/material_tokens_test.dart b/test/src/theme/tokens/material_tokens_test.dart new file mode 100644 index 000000000..e3da5e5f6 --- /dev/null +++ b/test/src/theme/tokens/material_tokens_test.dart @@ -0,0 +1,299 @@ +// ignore_for_file: deprecated_member_use, avoid-non-null-assertion + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/mix.dart'; + +// import '../../helpers/extensions/build_context_ext.dart'; +// import 'mix_token.dart'; +// import 'refs.dart'; + +// class MaterialColorToken extends MixToken { +// const MaterialColorToken(super.name); +// } + +// class _MaterialDesignColors { +// final primary = ResolvableColorToken( +// '--md-color-primary', +// (context) => context.colorScheme.primary, +// ); + +// final secondary = ResolvableColorToken( +// '--md-color-secondary', +// (context) => context.colorScheme.secondary, +// ); + +// final tertiary = ResolvableColorToken( +// '--md-color-tertiary', +// (context) => context.colorScheme.tertiary, +// ); + +// final surface = ResolvableColorToken( +// '--md-color-surface', +// (context) => context.colorScheme.surface, +// ); + +// final background = ResolvableColorToken( +// '--md-color-background', +// (context) => context.colorScheme.background, +// ); + +// final error = ResolvableColorToken( +// '--md-color-error', +// (context) => context.colorScheme.error, +// ); + +// final onPrimary = ResolvableColorToken( +// '--md-color-on-primary', +// (context) => context.colorScheme.onPrimary, +// ); + +// final onSecondary = ResolvableColorToken( +// '--md-color-on-secondary', +// (context) => context.colorScheme.onSecondary, +// ); + +// final onTertiary = ResolvableColorToken( +// '--md-color-on-tertiary', +// (context) => context.colorScheme.onTertiary, +// ); + +// final onSurface = ResolvableColorToken( +// '--md-color-on-surface', +// (context) => context.colorScheme.onSurface, +// ); + +// final onBackground = ResolvableColorToken( +// '--md-color-on-background', +// (context) => context.colorScheme.onBackground, +// ); + +// final onError = ResolvableColorToken( +// '--md-color-on-error', +// (context) => context.colorScheme.onError, +// ); + +// _MaterialDesignColors(); +// } + +// // Material 3 TextTheme Tokens. +// class MaterialTextStyles { +// // Material 3 text styles +// final displayLarge = ResolvableTextStyleToken( +// '--md3-displa-large', +// (context) => context.textTheme.displayLarge!, +// ); +// final displayMedium = ResolvableTextStyleToken( +// '--md3-displaymedium', +// (context) => context.textTheme.displayMedium!, +// ); +// final displaySmall = ResolvableTextStyleToken( +// '--md3-display-small', +// (context) => context.textTheme.displaySmall!, +// ); +// final headlineLarge = ResolvableTextStyleToken( +// '--md3-headline-large', +// (context) => context.textTheme.headlineLarge!, +// ); +// final headlineMedium = ResolvableTextStyleToken( +// '--md3-headline-medium', +// (context) => context.textTheme.headlineMedium!, +// ); +// final headlineSmall = ResolvableTextStyleToken( +// '--md3-headline-small', +// (context) => context.textTheme.headlineSmall!, +// ); +// final titleLarge = ResolvableTextStyleToken( +// '--md3-title-large', +// (context) => context.textTheme.titleLarge!, +// ); +// final titleMedium = ResolvableTextStyleToken( +// '--md3-title-medium', +// (context) => context.textTheme.titleMedium!, +// ); +// final titleSmall = ResolvableTextStyleToken( +// '--md3-title-small', +// (context) => context.textTheme.titleSmall!, +// ); +// final bodyLarge = ResolvableTextStyleToken( +// '--md3-body-large', +// (context) => context.textTheme.bodyLarge!, +// ); +// final bodyMedium = ResolvableTextStyleToken( +// '--md3-body-medium', +// (context) => context.textTheme.bodyMedium!, +// ); +// final bodySmall = ResolvableTextStyleToken( +// '--md3-body-small', +// (context) => context.textTheme.bodySmall!, +// ); +// final labelLarge = ResolvableTextStyleToken( +// '--md3-label-large', +// (context) => context.textTheme.labelLarge!, +// ); +// final labelMedium = ResolvableTextStyleToken( +// '--md3-label-medium', +// (context) => context.textTheme.labelMedium!, +// ); +// final labelSmall = ResolvableTextStyleToken( +// '--md3-label-small', +// (context) => context.textTheme.labelSmall!, +// ); +// // Material 2 text styles +// final headline1 = ResolvableTextStyleToken( +// '--md2-text-style-headline1', +// (context) => context.textTheme.headline1!, +// ); +// final headline2 = ResolvableTextStyleToken( +// '--md2-text-style-headline2', +// (context) => context.textTheme.headline2!, +// ); +// final headline3 = ResolvableTextStyleToken( +// '--md2-text-style-headline3', +// (context) => context.textTheme.headline3!, +// ); +// final headline4 = ResolvableTextStyleToken( +// '--md2-text-style-headline4', +// (context) => context.textTheme.headline4!, +// ); +// final headline5 = ResolvableTextStyleToken( +// '--md2-text-style-headline5', +// (context) => context.textTheme.headline5!, +// ); +// final headline6 = ResolvableTextStyleToken( +// '--md2-text-style-headline6', +// (context) => context.textTheme.headline6!, +// ); +// final subtitle1 = ResolvableTextStyleToken( +// '--md2-text-style-subtitle1', +// (context) => context.textTheme.subtitle1!, +// ); +// final subtitle2 = ResolvableTextStyleToken( +// '--md2-text-style-subtitle2', +// (context) => context.textTheme.subtitle2!, +// ); +// final bodyText1 = ResolvableTextStyleToken( +// '--md2-text-style-bodyText1', +// (context) => context.textTheme.bodyText1!, +// ); +// final bodyText2 = ResolvableTextStyleToken( +// '--md2-text-style-bodyText2', +// (context) => context.textTheme.bodyText2!, +// ); +// final caption = ResolvableTextStyleToken( +// '--md2-text-style-caption', +// (context) => context.textTheme.caption!, +// ); +// final button = ResolvableTextStyleToken( +// '--md2-text-style-button', +// (context) => context.textTheme.button!, +// ); +// final overline = ResolvableTextStyleToken( +// '--md2-text-style-overline', +// (context) => context.textTheme.overline!, +// ); + +// MaterialTextStyles(); +// } + +// final $md = _MaterialTokens(); + +// class _MaterialTokens { +// final colors = _MaterialDesignColors(); +// final textStyles = MaterialTextStyles(); +// _MaterialTokens(); +// } + +void main() { + // Create a test that checks if all the values of these tokens match the ThemeData from the MaterialApp + group('Material tokens', () { + testWidgets('colors', (tester) async { + final theme = ThemeData.light(); + await tester.pumpWidget( + MaterialApp(theme: theme, home: Container()), + ); + final context = tester.element(find.byType(Container)); + final colors = MaterialTokens().colors; + expect(colors.primary.resolve(context), theme.colorScheme.primary); + expect(colors.secondary.resolve(context), theme.colorScheme.secondary); + expect(colors.tertiary.resolve(context), theme.colorScheme.tertiary); + expect(colors.surface.resolve(context), theme.colorScheme.surface); + expect(colors.background.resolve(context), theme.colorScheme.background); + expect(colors.error.resolve(context), theme.colorScheme.error); + expect(colors.onPrimary.resolve(context), theme.colorScheme.onPrimary); + expect( + colors.onSecondary.resolve(context), theme.colorScheme.onSecondary); + expect(colors.onTertiary.resolve(context), theme.colorScheme.onTertiary); + expect(colors.onSurface.resolve(context), theme.colorScheme.onSurface); + expect( + colors.onBackground.resolve(context), + theme.colorScheme.onBackground, + ); + expect(colors.onError.resolve(context), theme.colorScheme.onError); + }); + + testWidgets('Material 3 textStyles', (tester) async { + await tester.pumpWidget( + MaterialApp( + theme: ThemeData.light(useMaterial3: true), home: Container()), + ); + final context = tester.element(find.byType(Container)); + + final theme = Theme.of(context); + + final textStyles = MaterialTokens().textStyles; + expect(textStyles.displayLarge.resolve(context), + theme.textTheme.displayLarge); + expect(textStyles.displayMedium.resolve(context), + theme.textTheme.displayMedium); + expect(textStyles.displaySmall.resolve(context), + theme.textTheme.displaySmall); + expect(textStyles.headlineLarge.resolve(context), + theme.textTheme.headlineLarge); + expect(textStyles.headlineMedium.resolve(context), + theme.textTheme.headlineMedium); + expect(textStyles.headlineSmall.resolve(context), + theme.textTheme.headlineSmall); + expect( + textStyles.titleLarge.resolve(context), theme.textTheme.titleLarge); + expect( + textStyles.titleMedium.resolve(context), theme.textTheme.titleMedium); + expect( + textStyles.titleSmall.resolve(context), theme.textTheme.titleSmall); + expect(textStyles.bodyLarge.resolve(context), theme.textTheme.bodyLarge); + expect( + textStyles.bodyMedium.resolve(context), theme.textTheme.bodyMedium); + expect(textStyles.bodySmall.resolve(context), theme.textTheme.bodySmall); + expect( + textStyles.labelLarge.resolve(context), theme.textTheme.labelLarge); + expect( + textStyles.labelMedium.resolve(context), theme.textTheme.labelMedium); + expect( + textStyles.labelSmall.resolve(context), theme.textTheme.labelSmall); + }); + + testWidgets('Material 2 text styles', (tester) async { + await tester.pumpWidget( + MaterialApp(theme: ThemeData.light(), home: Container()), + ); + final context = tester.element(find.byType(Container)); + + final theme = Theme.of(context); + + final textStyles = MaterialTokens().textStyles; + expect(textStyles.headline1.resolve(context), theme.textTheme.headline1); + expect(textStyles.headline2.resolve(context), theme.textTheme.headline2); + expect(textStyles.headline3.resolve(context), theme.textTheme.headline3); + expect(textStyles.headline4.resolve(context), theme.textTheme.headline4); + expect(textStyles.headline5.resolve(context), theme.textTheme.headline5); + expect(textStyles.headline6.resolve(context), theme.textTheme.headline6); + expect(textStyles.subtitle1.resolve(context), theme.textTheme.subtitle1); + expect(textStyles.subtitle2.resolve(context), theme.textTheme.subtitle2); + expect(textStyles.bodyText1.resolve(context), theme.textTheme.bodyText1); + expect(textStyles.bodyText2.resolve(context), theme.textTheme.bodyText2); + expect(textStyles.caption.resolve(context), theme.textTheme.caption); + expect(textStyles.button.resolve(context), theme.textTheme.button); + expect(textStyles.overline.resolve(context), theme.textTheme.overline); + }); + }); +} diff --git a/test/src/theme/tokens/radius_token_test.dart b/test/src/theme/tokens/radius_token_test.dart new file mode 100644 index 000000000..c910f3562 --- /dev/null +++ b/test/src/theme/tokens/radius_token_test.dart @@ -0,0 +1,142 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/mix.dart'; +import 'package:mix/src/theme/tokens/radius_token.dart'; + +import '../../../helpers/testing_utils.dart'; + +void main() { + group('RadiusToken', () { + test('Constructor assigns name correctly', () { + const radiusRef = RadiusToken('testName'); + expect(radiusRef.name, 'testName'); + }); + + test('Equality operator works correctly', () { + const radiusRef1 = RadiusToken('testName'); + const radiusRef2 = RadiusToken('testName'); + const radiusRef3 = RadiusToken('differentName'); + + expect(radiusRef1 == radiusRef2, isTrue); + expect(radiusRef1 == radiusRef3, isFalse); + expect(radiusRef1 == Object(), isFalse); + }); + + test('hashCode is consistent with name', () { + const radiusRef1 = RadiusToken('testName'); + const radiusRef2 = RadiusToken('testName'); + const radiusRef3 = RadiusToken('differentName'); + + expect(radiusRef1.hashCode, radiusRef2.hashCode); + expect(radiusRef1.hashCode, isNot(radiusRef3.hashCode)); + }); + + testWidgets('Test it resolves correctly', (tester) async { + const redRadiusRef = RadiusToken('red'); + const greenRadiusRef = RadiusToken('green'); + const blueRadiusRef = RadiusToken('blue'); + final theme = MixThemeData(radii: { + redRadiusRef: (_) => const Radius.circular(1), + greenRadiusRef: (_) => const Radius.circular(2), + blueRadiusRef: (_) => const Radius.circular(3), + }); + + await tester.pumpWidget(createWithMixTheme(theme)); + + final context = tester.element(find.byType(Container)); + + final mixData = MixData.create(context, StyleMix.empty); + + expect( + mixData.resolver.radiiToken(redRadiusRef), const Radius.circular(1)); + expect(mixData.resolver.radiiToken(greenRadiusRef), + const Radius.circular(2)); + expect( + mixData.resolver.radiiToken(blueRadiusRef), const Radius.circular(3)); + }); + }); + + group('RadiusTokenResolver', () { + test('Constructor assigns name correctly', () { + final radiusRef = RadiusTokenResolver('testName', (_) => Radius.zero); + expect(radiusRef.name, 'testName'); + }); + + test('Equality operator works correctly', () { + final radiusRef1 = + RadiusTokenResolver('testName', (_) => const Radius.circular(1)); + final radiusRef2 = + RadiusTokenResolver('testName', (_) => const Radius.circular(1)); + final radiusRef3 = + RadiusTokenResolver('differentName', (_) => const Radius.circular(1)); + + expect(radiusRef1 == radiusRef2, isTrue); + expect(radiusRef1 == radiusRef3, isFalse); + expect(radiusRef1 == Object(), isFalse); + }); + + test('hashCode is consistent with name', () { + final radiusRef1 = + RadiusTokenResolver('testName', (_) => const Radius.circular(1)); + final radiusRef2 = + RadiusTokenResolver('testName', (_) => const Radius.circular(1)); + final radiusRef3 = + RadiusTokenResolver('differentName', (_) => const Radius.circular(1)); + + expect(radiusRef1.hashCode, radiusRef2.hashCode); + expect(radiusRef1.hashCode, isNot(radiusRef3.hashCode)); + }); + + testWidgets('Test it resolves correctly', (tester) async { + final redRadiusRef = + RadiusTokenResolver('red', (_) => const Radius.circular(1)); + final greenRadiusRef = + RadiusTokenResolver('green', (_) => const Radius.circular(2)); + final blueRadiusRef = + RadiusTokenResolver('blue', (_) => const Radius.circular(3)); + + await tester.pumpMaterialApp(Container()); + + final context = tester.element(find.byType(Container)); + + final mixData = MixData.create(context, StyleMix.empty); + + expect( + mixData.resolver.radiiToken(redRadiusRef), const Radius.circular(1)); + expect(mixData.resolver.radiiToken(greenRadiusRef), + const Radius.circular(2)); + expect( + mixData.resolver.radiiToken(blueRadiusRef), const Radius.circular(3)); + }); + }); + + group('RadiiTokenUtil', () { + test('small returns correct value', () { + expect(const RadiiTokenUtil().small, RadiusToken.small); + }); + + test('medium returns correct value', () { + expect(const RadiiTokenUtil().medium, RadiusToken.medium); + }); + + test('large returns correct value', () { + expect(const RadiiTokenUtil().large, RadiusToken.large); + }); + }); + + group( + 'UtilityWithRadiusTokens', + () { + test( + 'tokens resolve', + () { + final radiiTokenUtil = UtilityWithRadiusTokens((value) => value); + + expect(radiiTokenUtil.small, RadiusToken.small); + expect(radiiTokenUtil.medium, RadiusToken.medium); + expect(radiiTokenUtil.large, RadiusToken.large); + }, + ); + }, + ); +} diff --git a/test/src/theme/tokens/space_token_test.dart b/test/src/theme/tokens/space_token_test.dart new file mode 100644 index 000000000..009f50c98 --- /dev/null +++ b/test/src/theme/tokens/space_token_test.dart @@ -0,0 +1,87 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/mix.dart'; + +void main() { + group('SpaceToken tests', () { + test('SpaceToken.xsmall() returns correct value', () { + expect(SpaceToken.xsmall(), SpaceToken.xsmall()); + expect(const SpaceToken('--mix-space-xsmall'), SpaceToken.xsmall); + expect('--mix-space-xsmall', SpaceToken.xsmall.name); + expect('--mix-space-xsmall'.hashCode, SpaceToken.xsmall.name.hashCode); + + expect(SpaceToken.xsmall(), lessThan(0)); + expect(SpaceToken.xsmall(), -1.0 * SpaceToken.xsmall.hashCode); + }); + + test('SpaceToken.small() returns correct value', () { + expect(SpaceToken.small(), SpaceToken.small()); + expect(const SpaceToken('--mix-space-small'), SpaceToken.small); + expect('--mix-space-small', SpaceToken.small.name); + expect('--mix-space-small'.hashCode, SpaceToken.small.name.hashCode); + + expect(SpaceToken.small(), lessThan(0)); + expect(SpaceToken.small(), -1.0 * SpaceToken.small.hashCode); + }); + + test('SpaceToken.medium() returns correct value', () { + expect(SpaceToken.medium(), SpaceToken.medium()); + expect(const SpaceToken('--mix-space-medium'), SpaceToken.medium); + expect('--mix-space-medium', SpaceToken.medium.name); + expect('--mix-space-medium'.hashCode, SpaceToken.medium.name.hashCode); + + expect(SpaceToken.medium(), lessThan(0)); + expect(SpaceToken.medium(), -1.0 * SpaceToken.medium.hashCode); + }); + + test('SpaceToken.large() returns correct value', () { + expect(SpaceToken.large(), SpaceToken.large()); + expect(const SpaceToken('--mix-space-large'), SpaceToken.large); + expect('--mix-space-large', SpaceToken.large.name); + expect('--mix-space-large'.hashCode, SpaceToken.large.name.hashCode); + }); + + test('SpaceToken.xlarge() returns correct value', () { + expect(SpaceToken.xlarge(), SpaceToken.xlarge()); + expect(const SpaceToken('--mix-space-xlarge'), SpaceToken.xlarge); + expect('--mix-space-xlarge', SpaceToken.xlarge.name); + expect('--mix-space-xlarge'.hashCode, SpaceToken.xlarge.name.hashCode); + + expect(SpaceToken.xlarge(), lessThan(0)); + expect(SpaceToken.xlarge(), -1.0 * SpaceToken.xlarge.hashCode); + }); + + test('SpaceToken.xxlarge() returns correct value', () { + expect(SpaceToken.xxlarge(), SpaceToken.xxlarge()); + expect(const SpaceToken('--mix-space-xxlarge'), SpaceToken.xxlarge); + expect('--mix-space-xxlarge', SpaceToken.xxlarge.name); + expect('--mix-space-xxlarge'.hashCode, SpaceToken.xxlarge.name.hashCode); + + expect(SpaceToken.xxlarge(), lessThan(0)); + expect(SpaceToken.xxlarge(), -1.0 * SpaceToken.xxlarge.hashCode); + }); + }); + + group('WithSpaceTokens tests', () { + test('WithSpaceTokens returns correct value', () { + final withSpaceTokens = UtilityWithSpaceTokens((value) => value); + expect(withSpaceTokens.xsmall, SpaceToken.xsmall()); + expect(withSpaceTokens.small, SpaceToken.small()); + expect(withSpaceTokens.medium, SpaceToken.medium()); + expect(withSpaceTokens.large, SpaceToken.large()); + expect(withSpaceTokens.xlarge, SpaceToken.xlarge()); + expect(withSpaceTokens.xxlarge, SpaceToken.xxlarge()); + }); + }); + + group('SpaceTokenUtil', () { + test('SpaceTokenUtil returns correct value', () { + final spaceTokenUtil = SpaceTokenUtil(); + expect(spaceTokenUtil.xsmall, SpaceToken.xsmall()); + expect(spaceTokenUtil.small, SpaceToken.small()); + expect(spaceTokenUtil.medium, SpaceToken.medium()); + expect(spaceTokenUtil.large, SpaceToken.large()); + expect(spaceTokenUtil.xlarge, SpaceToken.xlarge()); + expect(spaceTokenUtil.xxlarge, SpaceToken.xxlarge()); + }); + }); +} diff --git a/test/src/theme/tokens/text_style_token_test.dart b/test/src/theme/tokens/text_style_token_test.dart new file mode 100644 index 000000000..7224afac5 --- /dev/null +++ b/test/src/theme/tokens/text_style_token_test.dart @@ -0,0 +1,118 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/src/factory/mix_provider_data.dart'; +import 'package:mix/src/factory/style_mix.dart'; +import 'package:mix/src/theme/mix_theme.dart'; +import 'package:mix/src/theme/tokens/text_style_token.dart'; + +import '../../../helpers/testing_utils.dart'; + +void main() { + group('TextStyleToken', () { + test('Constructor assigns name correctly', () { + const textStyleToken = TextStyleToken('testName'); + expect(textStyleToken.name, 'testName'); + }); + + test('Equality operator works correctly', () { + const textStyleToken1 = TextStyleToken('testName'); + const textStyleToken2 = TextStyleToken('testName'); + const textStyleToken3 = TextStyleToken('differentName'); + + expect(textStyleToken1 == textStyleToken2, isTrue); + expect(textStyleToken1 == textStyleToken3, isFalse); + expect(textStyleToken1 == Object(), isFalse); + }); + + test('hashCode is consistent with name', () { + const textStyleToken1 = TextStyleToken('testName'); + const textStyleToken2 = TextStyleToken('testName'); + const textStyleToken3 = TextStyleToken('differentName'); + + expect(textStyleToken1.hashCode, textStyleToken2.hashCode); + expect(textStyleToken1.hashCode, isNot(textStyleToken3.hashCode)); + }); + + testWidgets('Test it resolves correctly', (tester) async { + const redtextStyleToken = TextStyleToken('red'); + const greentextStyleToken = TextStyleToken('green'); + const bluetextStyleToken = TextStyleToken('blue'); + final theme = MixThemeData( + textStyles: { + redtextStyleToken: (_) => const TextStyle(color: Colors.red), + greentextStyleToken: (_) => const TextStyle(color: Colors.green), + bluetextStyleToken: (_) => const TextStyle(color: Colors.blue), + }, + ); + + await tester.pumpWidget(createWithMixTheme(theme)); + + final context = tester.element(find.byType(Container)); + + final mixData = MixData.create(context, StyleMix.empty); + + expect(mixData.resolver.textStyleToken(redtextStyleToken), + const TextStyle(color: Colors.red)); + expect(mixData.resolver.textStyleToken(greentextStyleToken), + const TextStyle(color: Colors.green)); + expect(mixData.resolver.textStyleToken(bluetextStyleToken), + const TextStyle(color: Colors.blue)); + }); + }); + + // Resolvable TextStyle Token + group('TextStyleResolvableToken', () { + test('Constructor assigns name correctly', () { + final textStyleToken = + TextStyleTokenResolver('testName', (_) => const TextStyle()); + expect(textStyleToken.name, 'testName'); + }); + + test('Equality operator works correctly', () { + final textStyleToken1 = + TextStyleTokenResolver('testName', (_) => const TextStyle()); + final textStyleToken2 = + TextStyleTokenResolver('testName', (_) => const TextStyle()); + final textStyleToken3 = + TextStyleTokenResolver('differentName', (_) => const TextStyle()); + + expect(textStyleToken1 == textStyleToken2, isTrue); + expect(textStyleToken1 == textStyleToken3, isFalse); + expect(textStyleToken1 == Object(), isFalse); + }); + + test('hashCode is consistent with name', () { + final textStyleToken1 = + TextStyleTokenResolver('testName', (_) => const TextStyle()); + final textStyleToken2 = + TextStyleTokenResolver('testName', (_) => const TextStyle()); + final textStyleToken3 = + TextStyleTokenResolver('differentName', (_) => const TextStyle()); + + expect(textStyleToken1.hashCode, textStyleToken2.hashCode); + expect(textStyleToken1.hashCode, isNot(textStyleToken3.hashCode)); + }); + + testWidgets('Test it resolves correctly', (tester) async { + final redtextStyleToken = TextStyleTokenResolver( + 'red', (_) => const TextStyle(color: Colors.red)); + final greentextStyleToken = TextStyleTokenResolver( + 'green', (_) => const TextStyle(color: Colors.green)); + final bluetextStyleToken = TextStyleTokenResolver( + 'blue', (_) => const TextStyle(color: Colors.blue)); + + await tester.pumpMaterialApp(Container()); + + final context = tester.element(find.byType(Container)); + + final mixData = MixData.create(context, StyleMix.empty); + + expect(mixData.resolver.textStyleToken(redtextStyleToken), + const TextStyle(color: Colors.red)); + expect(mixData.resolver.textStyleToken(greentextStyleToken), + const TextStyle(color: Colors.green)); + expect(mixData.resolver.textStyleToken(bluetextStyleToken), + const TextStyle(color: Colors.blue)); + }); + }); +} diff --git a/test/src/utils/alignment_util_test.dart b/test/src/utils/alignment_util_test.dart new file mode 100644 index 000000000..82781ca36 --- /dev/null +++ b/test/src/utils/alignment_util_test.dart @@ -0,0 +1,120 @@ +import 'package:flutter/src/painting/alignment.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/mix.dart'; + +import '../../helpers/testing_utils.dart'; + +void main() { + group('AlignmentGeometryAttribute utilities:', () { + test('"alignment" takes in x and y and returns AlignmentAttribute', () { + var result = alignment(0, 1); + + expect(result, isA()); + expect(result, isA()); + expect(result.x, 0); + expect(result.y, 1); + }); + + test( + "alignmentDirectional takes in start and y and returns AlignmentDirectionalAttribute", + () { + var result = alignmentDirectional(0, 1); + + expect(result, isA()); + expect(result, isA()); + expect(result.start, 0); + expect(result.y, 1); + }); + + test( + 'predefined functions return correct AlignmentAttribute and resolves correctly', + () { + // alignmentTopLeft + expect(alignmentTopLeft(), isA()); + expect(alignmentTopLeft(), isA()); + expect(alignmentTopLeft().resolve(EmptyMixData), Alignment.topLeft); + + // alignmentTopCenter + expect(alignmentTopCenter(), isA()); + expect(alignmentTopCenter(), isA()); + expect(alignmentTopCenter().resolve(EmptyMixData), Alignment.topCenter); + + // alignmentTopRight + expect(alignmentTopRight(), isA()); + expect(alignmentTopRight(), isA()); + expect(alignmentTopRight().resolve(EmptyMixData), Alignment.topRight); + + // alignmentCenterLeft + expect(alignmentCenterLeft(), isA()); + expect(alignmentCenterLeft(), isA()); + expect(alignmentCenterLeft().resolve(EmptyMixData), Alignment.centerLeft); + + // alignmentCenter + expect(alignmentCenter(), isA()); + expect(alignmentCenter(), isA()); + expect(alignmentCenter().resolve(EmptyMixData), Alignment.center); + + // alignmentCenterRight + expect(alignmentCenterRight(), isA()); + expect(alignmentCenterRight(), isA()); + expect( + alignmentCenterRight().resolve(EmptyMixData), Alignment.centerRight); + + // alignmentBottomLeft + expect(alignmentBottomLeft(), isA()); + expect(alignmentBottomLeft(), isA()); + expect(alignmentBottomLeft().resolve(EmptyMixData), Alignment.bottomLeft); + + // alignmentBottomCenter + expect(alignmentBottomCenter(), isA()); + expect(alignmentBottomCenter(), isA()); + expect(alignmentBottomCenter().resolve(EmptyMixData), + Alignment.bottomCenter); + + // alignmentBottomRight + expect(alignmentBottomRight(), isA()); + expect(alignmentBottomRight(), isA()); + expect( + alignmentBottomRight().resolve(EmptyMixData), Alignment.bottomRight); + }); + test( + 'predefined functions return correct AlignmentDirectionalAttribute and resolves correctly', + () { + // alignmentTopStart + expect(alignmentTopStart(), isA()); + expect(alignmentTopStart(), isA()); + expect(alignmentTopStart().resolve(EmptyMixData), + AlignmentDirectional.topStart); + + // alignmentTopEnd + expect(alignmentTopEnd(), isA()); + expect(alignmentTopEnd(), isA()); + expect( + alignmentTopEnd().resolve(EmptyMixData), AlignmentDirectional.topEnd); + + // alignmentCenterStart + expect(alignmentCenterStart(), isA()); + expect(alignmentCenterStart(), isA()); + expect(alignmentCenterStart().resolve(EmptyMixData), + AlignmentDirectional.centerStart); + + // alignmentCenterEnd + expect(alignmentCenterEnd(), isA()); + expect(alignmentCenterEnd(), isA()); + expect(alignmentCenterEnd().resolve(EmptyMixData), + AlignmentDirectional.centerEnd); + + // alignmentBottomStart + expect(alignmentBottomStart(), isA()); + expect(alignmentBottomStart(), isA()); + expect(alignmentBottomStart().resolve(EmptyMixData), + AlignmentDirectional.bottomStart); + + // alignmentBottomEnd + expect(alignmentBottomEnd(), isA()); + expect(alignmentBottomEnd(), isA()); + expect(alignmentBottomEnd().resolve(EmptyMixData), + AlignmentDirectional.bottomEnd); + }); + }); +} diff --git a/test/src/utils/border_radius_util_test.dart b/test/src/utils/border_radius_util_test.dart new file mode 100644 index 000000000..1be4cc81d --- /dev/null +++ b/test/src/utils/border_radius_util_test.dart @@ -0,0 +1,197 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/mix.dart'; + +import '../../helpers/testing_utils.dart'; + +void main() { + group('BorderRadiusAttribute', () { + test('borderRadius()', () { + final attr = borderRadius(const Radius.circular(10)); + expect( + attr.resolve(EmptyMixData), + const BorderRadius.all( + Radius.circular(10), + )); + }); + + test('borderRadiusVertical()', () { + final attr = borderRadiusVertical( + top: const Radius.circular(10), + bottom: const Radius.circular(20), + ); + expect( + attr.resolve(EmptyMixData), + const BorderRadius.vertical( + top: Radius.circular(10), + bottom: Radius.circular(20), + )); + }); + + test('borderRadiusHorizontal()', () { + final attr = borderRadiusHorizontal( + left: const Radius.circular(10), + right: const Radius.circular(20), + ); + expect( + attr.resolve(EmptyMixData), + const BorderRadius.horizontal( + left: Radius.circular(10), + right: Radius.circular(20), + )); + }); + + test('borderRadiusZero()', () { + final attr = borderRadius(Radius.zero); + expect( + attr.resolve(EmptyMixData), + const BorderRadius.all( + Radius.zero, + )); + }); + + test('borderRadiusOnly()', () { + final attr = borderRadiusOnly( + topLeft: const Radius.circular(10), + topRight: const Radius.circular(20), + bottomLeft: const Radius.circular(30), + bottomRight: const Radius.circular(40), + ); + expect( + attr.resolve(EmptyMixData), + const BorderRadius.only( + topLeft: Radius.circular(10), + topRight: Radius.circular(20), + bottomLeft: Radius.circular(30), + bottomRight: Radius.circular(40), + )); + }); + + test('borderRadiusDirectional()', () { + final attr = borderRadiusDirectional(const Radius.circular(10)); + expect( + attr.resolve(EmptyMixData), + const BorderRadiusDirectional.all( + Radius.circular(10), + )); + }); + }); + + group('Rounded utilities', () { + test('rounded()', () { + final attr = rounded(10, 20, 30, 40); + expect( + attr.resolve(EmptyMixData), + const BorderRadius.only( + topLeft: Radius.circular(10), + topRight: Radius.circular(20), + bottomLeft: Radius.circular(30), + bottomRight: Radius.circular(40), + )); + }); + + test('roundedDirectional()', () { + final attr = roundedDirectional(10, 20, 30, 40); + expect( + attr.resolve(EmptyMixData), + const BorderRadiusDirectional.only( + topStart: Radius.circular(10), + topEnd: Radius.circular(20), + bottomStart: Radius.circular(30), + bottomEnd: Radius.circular(40), + )); + }); + + test('roundedTopLeft()', () { + final attr = roundedTopLeft(10); + expect( + attr.resolve(EmptyMixData), + const BorderRadius.only( + topLeft: Radius.circular(10), + )); + }); + + test('roundedTopRight()', () { + final attr = roundedTopRight(10); + expect( + attr.resolve(EmptyMixData), + const BorderRadius.only( + topRight: Radius.circular(10), + )); + }); + + test('roundedBottomLeft()', () { + final attr = roundedBottomLeft(10); + expect( + attr.resolve(EmptyMixData), + const BorderRadius.only( + bottomLeft: Radius.circular(10), + )); + }); + + test('roundedBottomRight()', () { + final attr = roundedBottomRight(10); + expect( + attr.resolve(EmptyMixData), + const BorderRadius.only( + bottomRight: Radius.circular(10), + )); + }); + + test('roundedTopStart()', () { + final attr = roundedTopStart(10); + expect( + attr.resolve(EmptyMixData), + const BorderRadiusDirectional.only( + topStart: Radius.circular(10), + )); + }); + + test('roundedTopEnd()', () { + final attr = roundedTopEnd(10); + expect( + attr.resolve(EmptyMixData), + const BorderRadiusDirectional.only( + topEnd: Radius.circular(10), + )); + }); + + test('roundedBottomStart()', () { + final attr = roundedBottomStart(10); + expect( + attr.resolve(EmptyMixData), + const BorderRadiusDirectional.only( + bottomStart: Radius.circular(10), + )); + }); + + test('roundedBottomEnd()', () { + final attr = roundedBottomEnd(10); + expect( + attr.resolve(EmptyMixData), + const BorderRadiusDirectional.only( + bottomEnd: Radius.circular(10), + )); + }); + + test('roundedHorizontal()', () { + final attr = roundedHorizontal(left: 10, right: 20); + expect( + attr.resolve(EmptyMixData), + const BorderRadius.horizontal( + left: Radius.circular(10), + right: Radius.circular(20), + )); + }); + + test('roundedVertical()', () { + final attr = roundedVertical(top: 10, bottom: 20); + expect( + attr.resolve(EmptyMixData), + const BorderRadius.vertical( + top: Radius.circular(10), + bottom: Radius.circular(20), + )); + }); + }); +} diff --git a/test/src/utils/border_util_test.dart b/test/src/utils/border_util_test.dart new file mode 100644 index 000000000..cc185280d --- /dev/null +++ b/test/src/utils/border_util_test.dart @@ -0,0 +1,126 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/mix.dart'; + +void main() { + group('Border Util Tests', () { + test('borderTop()', () { + final result = borderTop( + color: Colors.red, + width: 10.0, + style: BorderStyle.solid, + strokeAlign: 0.5); + expect(result.top?.color?.value, Colors.red); + expect(result.top?.width, 10.0); + expect(result.top?.style, BorderStyle.solid); + expect(result.top?.strokeAlign, 0.5); + expect(result.right, null); + expect(result.bottom, null); + expect(result.left, null); + }); + + test('borderBottom()', () { + final result = borderBottom( + color: Colors.red, + width: 10.0, + style: BorderStyle.solid, + strokeAlign: 0.5); + expect(result.bottom?.color?.value, Colors.red); + expect(result.bottom?.width, 10.0); + expect(result.bottom?.style, BorderStyle.solid); + expect(result.bottom?.strokeAlign, 0.5); + expect(result.right, null); + expect(result.top, null); + expect(result.left, null); + }); + + test('borderLeft()', () { + final result = borderLeft( + color: Colors.red, + width: 10.0, + style: BorderStyle.solid, + strokeAlign: 0.5); + expect(result.left?.color?.value, Colors.red); + expect(result.left?.width, 10.0); + expect(result.left?.style, BorderStyle.solid); + expect(result.left?.strokeAlign, 0.5); + expect(result.right, null); + expect(result.top, null); + expect(result.bottom, null); + }); + + test('borderRight()', () { + final result = borderRight( + color: Colors.red, + width: 10.0, + style: BorderStyle.solid, + strokeAlign: 0.5); + expect(result.right?.color?.value, Colors.red); + expect(result.right?.width, 10.0); + expect(result.right?.style, BorderStyle.solid); + expect(result.right?.strokeAlign, 0.5); + expect(result.left, null); + expect(result.top, null); + expect(result.bottom, null); + }); + + test('borderHorizontal()', () { + final result = borderHorizontal( + color: Colors.blue, + width: 5.0, + style: BorderStyle.solid, + strokeAlign: 0.3); + expect(result.top?.color?.value, Colors.blue); + expect(result.top?.width, 5.0); + expect(result.top?.style, BorderStyle.solid); + expect(result.top?.strokeAlign, 0.3); + expect(result.bottom?.color?.value, Colors.blue); + expect(result.bottom?.width, 5.0); + expect(result.bottom?.style, BorderStyle.solid); + expect(result.bottom?.strokeAlign, 0.3); + expect(result.left, null); + expect(result.right, null); + }); + + test('borderVertical()', () { + final result = borderVertical( + color: Colors.green, + width: 7.0, + style: BorderStyle.solid, + strokeAlign: 0.2); + expect(result.left?.color?.value, Colors.green); + expect(result.left?.width, 7.0); + expect(result.left?.style, BorderStyle.solid); + expect(result.left?.strokeAlign, 0.2); + expect(result.right?.color?.value, Colors.green); + expect(result.right?.width, 7.0); + expect(result.right?.style, BorderStyle.solid); + expect(result.right?.strokeAlign, 0.2); + expect(result.top, null); + expect(result.bottom, null); + }); + + test('borderSymetric()', () { + final verticalSide = borderVertical( + color: Colors.purple, + width: 4.0, + style: BorderStyle.none, + strokeAlign: 1.0, + ); + final horizontalSide = borderHorizontal( + color: Colors.orange, + width: 2.0, + style: BorderStyle.none, + strokeAlign: 0.0, + ); + + final result = verticalSide.merge(horizontalSide); + + expect(result.left, verticalSide.left); + expect(result.right, verticalSide.right); + expect(result.top, horizontalSide.top); + expect(result.bottom, horizontalSide.bottom); + expect(result, isA()); + }); + }); +} diff --git a/test/src/utils/box_constraints_util_test.dart b/test/src/utils/box_constraints_util_test.dart new file mode 100644 index 000000000..ed49edf02 --- /dev/null +++ b/test/src/utils/box_constraints_util_test.dart @@ -0,0 +1,74 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/mix.dart'; + +void main() { + group('BoxConstraintsAttribute Utilities', () { + test('boxConstraints()', () { + final result = boxConstraints( + minWidth: 50.0, + maxWidth: 150.0, + minHeight: 100.0, + maxHeight: 200.0, + ); + expect(result.minWidth, 50.0); + expect(result.maxWidth, 150.0); + expect(result.minHeight, 100.0); + expect(result.maxHeight, 200.0); + }); + + test('minWidth()', () { + final result = minWidth(50.0); + expect(result.minWidth, 50.0); + expect(result.maxWidth, isNull); + expect(result.minHeight, isNull); + expect(result.maxHeight, isNull); + }); + + test('maxWidth()', () { + final result = maxWidth(150.0); + expect(result.minWidth, isNull); + expect(result.maxWidth, 150.0); + expect(result.minHeight, isNull); + expect(result.maxHeight, isNull); + }); + + test('minHeight()', () { + final result = minHeight(100.0); + expect(result.minWidth, isNull); + expect(result.maxWidth, isNull); + expect(result.minHeight, 100.0); + expect(result.maxHeight, isNull); + }); + + test('maxHeight()', () { + final result = maxHeight(200.0); + expect(result.minWidth, isNull); + expect(result.maxWidth, isNull); + expect(result.minHeight, isNull); + expect(result.maxHeight, 200.0); + }); + + // width + test('width()', () { + final result = width(50.0); + + expect(result.minWidth, isNull); + expect(result.maxWidth, isNull); + expect(result.width, 50.0); + expect(result.minHeight, isNull); + expect(result.maxHeight, isNull); + expect(result.height, isNull); + }); + + // height + test('height()', () { + final result = height(50.0); + expect(result.minWidth, isNull); + expect(result.maxWidth, isNull); + expect(result.height, 50.0); + expect(result.minHeight, isNull); + expect(result.maxHeight, isNull); + expect(result.width, isNull); + }); + }); +} diff --git a/test/src/utils/context_variant_util_test.dart b/test/src/utils/context_variant_util_test.dart new file mode 100644 index 000000000..932aa708e --- /dev/null +++ b/test/src/utils/context_variant_util_test.dart @@ -0,0 +1,160 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/mix.dart'; + +import '../../helpers/testing_utils.dart'; + +void main() { + group('ContextVariant', () { + test('Equality holds when all properties are the same', () { + bool contextFunction(BuildContext context) => true; + final variant1 = ContextVariant('variant1', when: contextFunction); + final variant2 = ContextVariant('variant1', when: contextFunction); + expect(variant1, variant2); + }); + test('Equality fails when properties are different', () { + final variant1 = ContextVariant('variant1', when: (context) => true); + final variant2 = ContextVariant('variant2', when: (context) => true); + expect(variant1, isNot(variant2)); + }); + }); + group('Breakpoint Utils', () { + const xSmallScreenWidth = Size(320, 480); + const smallScreenWidth = Size(640, 480); + const mediumScreenWidth = Size(1240, 768); + const largeScreenWidth = Size(1440, 900); + testWidgets('xSmall screen context variant', (tester) async { + await tester.pumpWidget(createMediaQuery(xSmallScreenWidth)); + var context = tester.element(find.byType(Container)); + + expect(onXSmall.when(context), true, reason: 'xsmall'); + expect(onSmall.when(context), false, reason: 'small'); + expect(onMedium.when(context), false, reason: 'medium'); + expect(onLarge.when(context), false, reason: 'large'); + }); + + testWidgets('small screen context variant', (tester) async { + await tester.pumpWidget(createMediaQuery(smallScreenWidth)); + var context = tester.element(find.byType(Container)); + + expect(onXSmall.when(context), false, reason: 'xsmall'); + expect(onSmall.when(context), true, reason: 'small'); + expect(onMedium.when(context), false, reason: 'medium'); + expect(onLarge.when(context), false, reason: 'large'); + }); + + testWidgets('medium screen context variant', (tester) async { + await tester.pumpWidget(createMediaQuery(mediumScreenWidth)); + var context = tester.element(find.byType(Container)); + + expect(onXSmall.when(context), false, reason: 'xsmall'); + expect(onSmall.when(context), false, reason: 'small'); + expect(onMedium.when(context), true, reason: 'medium'); + expect(onLarge.when(context), false, reason: 'large'); + }); + + testWidgets('large screen context variant', (tester) async { + await tester.pumpWidget(createMediaQuery(largeScreenWidth)); + var context = tester.element(find.byType(Container)); + + expect(onXSmall.when(context), false, reason: 'xsmall'); + expect(onSmall.when(context), false, reason: 'small'); + expect(onMedium.when(context), false, reason: 'medium'); + expect(onLarge.when(context), true, reason: 'large'); + }); + + test('have correct variant names', () { + expect(onXSmall.name, 'on-mix-breakpoint-xsmall'); + expect(onSmall.name, 'on-mix-breakpoint-small'); + expect(onMedium.name, 'on-mix-breakpoint-medium'); + expect(onLarge.name, 'on-mix-breakpoint-large'); + }); + }); + + group('Brightness Utils', () { + testWidgets('onLight context variant', (tester) async { + await tester.pumpWidget(createBrightnessTheme(Brightness.light)); + var context = tester.element(find.byType(Container)); + + expect(onLight.when(context), true, reason: 'light'); + expect(onDark.when(context), false, reason: 'dark'); + }); + + testWidgets('onDark context variant', (widgetTester) async { + await widgetTester.pumpWidget(createBrightnessTheme(Brightness.dark)); + var context = widgetTester.element(find.byType(Container)); + + expect(onLight.when(context), false, reason: 'light'); + expect(onDark.when(context), true, reason: 'dark'); + }); + test('have correct variant names', () { + expect(onLight.name, 'on-light'); + expect(onDark.name, 'on-dark'); + }); + }); + + group('Directionality Utils', () { + testWidgets('onRTL context variant', (tester) async { + await tester.pumpWidget(createDirectionality(TextDirection.rtl)); + var context = tester.element(find.byType(Container)); + + expect(onRTL.when(context), true, reason: 'rtl'); + expect(onLTR.when(context), false, reason: 'ltr'); + }); + + testWidgets('onLTR context variant', (tester) async { + await tester.pumpWidget(createDirectionality(TextDirection.ltr)); + var context = tester.element(find.byType(Container)); + + expect(onRTL.when(context), false, reason: 'rtl'); + expect(onLTR.when(context), true, reason: 'ltr'); + }); + test('have correct variant names', () { + expect(onRTL.name, 'on-rtl'); + expect(onLTR.name, 'on-ltr'); + }); + }); + + group('Orientation Utils', () { + testWidgets('onPortrait context variant', (tester) async { + tester.view.physicalSize = const Size(400, 600); + await tester.pumpWidget(Container()); + var context = tester.element(find.byType(Container)); + + expect(onPortrait.when(context), true, reason: 'portrait'); + expect(onLandscape.when(context), false, reason: 'landscape'); + + addTearDown(tester.view.resetPhysicalSize); + }); + + testWidgets('onLandscape context variant', (tester) async { + tester.view.physicalSize = const Size(600, 400); + await tester.pumpWidget(Container()); + var context = tester.element(find.byType(Container)); + + expect(onPortrait.when(context), false, reason: 'portrait'); + expect(onLandscape.when(context), true, reason: 'landscape'); + addTearDown(tester.view.resetPhysicalSize); + }); + test('have correct variant names', () { + expect(onPortrait.name, 'on-portrait'); + expect(onLandscape.name, 'on-landscape'); + }); + }); + + group('Not Utils', () { + testWidgets('reverts when of context variant', (tester) async { + await tester.pumpWidget(createBrightnessTheme(Brightness.light)); + var context = tester.element(find.byType(Container)); + + expect(onLight.when(context), true, reason: 'light'); + expect(onDark.when(context), false, reason: 'dark'); + + final notLight = onNot(onLight); + final notDark = onNot(onDark); + + expect(notLight.when(context), false, reason: 'not light'); + expect(notDark.when(context), true, reason: 'not dark'); + }); + }); +} diff --git a/test/src/utils/decorators_util_test.dart b/test/src/utils/decorators_util_test.dart new file mode 100644 index 000000000..87af1fef9 --- /dev/null +++ b/test/src/utils/decorators_util_test.dart @@ -0,0 +1,93 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/mix.dart'; +import 'package:mix/src/decorators/clip_decorator.dart'; +import 'package:mix/src/utils/decorators_util.dart'; + +import '../../helpers/testing_utils.dart'; + +void main() { + group('Decorators', () { + test('aspectRatio creates AspectRatioDecorator correctly', () { + final aspectRatioDecorator = aspectRatio(2.0); + + expect(aspectRatioDecorator.aspectRatio, 2.0); + }); + + test('expanded creates FlexibleDecorator correctly', () { + final flexibleDecorator = expanded(); + + expect(flexibleDecorator.flexFit, FlexFit.tight); + }); + + test('flexible creates FlexibleDecorator correctly', () { + final flexibleDecorator = flexible(); + + expect(flexibleDecorator.flexFit, FlexFit.loose); + }); + + test('opacity creates OpacityDecorator correctly', () { + final opacityDecorator = opacity(0.5); + + expect(opacityDecorator.value, 0.5); + }); + + test('rotate creates RotateDecorator correctly', () { + final rotateDecorator = rotate(2); + + expect(rotateDecorator.value, 2); + }); + + test('rotate90 creates RotateDecorator correctly', () { + final rotateDecorator = rotate90(); + + expect(rotateDecorator.value, 1); + }); + + test('rotate180 creates RotateDecorator correctly', () { + final rotateDecorator = rotate180(); + + expect(rotateDecorator.value, 2); + }); + + test('rotate270 creates RotateDecorator correctly', () { + final rotateDecorator = rotate270(); + + expect(rotateDecorator.value, 3); + }); + + test('scale creates ScaleDecorator correctly', () { + final scaleDecorator = scale(0.5); + + expect(scaleDecorator.scale, 0.5); + }); + + test('clipRRect creates ClipRRectDecorator correctly', () { + final clipRRectDecorator = clipRRect(10.0); + + expect(clipRRectDecorator.borderRadius, BorderRadius.circular(10.0)); + }); + + test('clipOval creates ClipOvalDecorator correctly', () { + final clipOvalDecorator = clipOval(); + + expect(clipOvalDecorator.render(const Empty(), EmptyMixData), + isA()); + }); + + test('clipPath creates ClipPathDecorator correctly', () { + final clipPathDecorator = clipPath(); + + expect(clipPathDecorator.render(const Empty(), EmptyMixData), + isA()); + }); + + test('clipTriangle creates ClipPathDecorator correctly', () { + final clipTriangleDecorator = clipTriangle(); + + expect(clipTriangleDecorator.render(const Empty(), EmptyMixData), + isA()); + expect(clipTriangleDecorator.clipper, isA()); + }); + }); +} diff --git a/test/src/utils/gradient_util_test.dart b/test/src/utils/gradient_util_test.dart new file mode 100644 index 000000000..a765f148e --- /dev/null +++ b/test/src/utils/gradient_util_test.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/mix.dart'; + +void main() { + group('Gradient Creation Tests', () { + test('LinearGradient is created with correct parameters', () { + final colors = [Colors.red, Colors.blue]; + final attr = linearGradient( + colors: colors, + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ); + + final linearGradientValue = attr.value as LinearGradient; + expect(linearGradientValue, isA()); + + expect(linearGradientValue.begin, Alignment.topLeft); + expect(linearGradientValue.end, Alignment.bottomRight); + expect(linearGradientValue.colors, equals(colors)); + }); + + test('LinearGradient uses default values when parameters are not provided', + () { + final colors = [Colors.red, Colors.blue]; + final attr = linearGradient(colors: colors); + + final linearGradientValue = attr.value as LinearGradient; + expect(linearGradientValue, isA()); + expect(linearGradientValue.begin, LinearGradient(colors: colors).begin); + expect(linearGradientValue.end, LinearGradient(colors: colors).end); + }); + + test('RadialGradient is created with correct parameters', () { + final colors = [Colors.red, Colors.blue]; + final attr = + radialGradient(colors: colors, center: Alignment.center, radius: 0.5); + final radialGradientValue = attr.value as RadialGradient; + expect(radialGradientValue, isA()); + + expect(radialGradientValue.center, Alignment.center); + expect(radialGradientValue.radius, 0.5); + expect(radialGradientValue.colors, equals(colors)); + }); + + test('RadialGradient uses default values when parameters are not provided', + () { + final colors = [Colors.red, Colors.blue]; + final attr = radialGradient(colors: colors); + + final radialGradientValue = attr.value as RadialGradient; + expect(radialGradientValue, isA()); + expect(radialGradientValue.center, RadialGradient(colors: colors).center); + expect(radialGradientValue.radius, RadialGradient(colors: colors).radius); + }); + }); +} diff --git a/test/src/utils/pressable_util_test.dart b/test/src/utils/pressable_util_test.dart new file mode 100644 index 000000000..af6fd62f8 --- /dev/null +++ b/test/src/utils/pressable_util_test.dart @@ -0,0 +1,126 @@ +// Import necessary packages +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/mix.dart'; + +import '../../helpers/testing_utils.dart'; + +void main() { + group('Pressable Util', () { + const attribute1 = MockBooleanScalarAttribute(true); + const attribute2 = MockStringScalarAttribute('attribute2'); + const attribute3 = MockIntScalarAttribute(3); + testWidgets('press state', (tester) async { + await tester.pumpWithPressable( + Container(), + state: PressableState.pressed, + focus: true, + ); + + final context = tester.element(find.byType(Container)); + + final onPressAttr = onPress(attribute1, attribute2, attribute3); + + expect(onPressAttr.when(context), true); + expect(onPressAttr.value, StyleMix(attribute1, attribute2, attribute3)); + expect(onPressAttr.variant.name, 'on-pressed'); + expect(onPressAttr.variant.when(context), true); + }); + + testWidgets('long press state', (tester) async { + await tester.pumpWithPressable( + Container(), + state: PressableState.longPressed, + focus: true, + ); + + final context = tester.element(find.byType(Container)); + + final onLongPressAttr = onLongPress(attribute1, attribute2, attribute3); + + expect(onLongPressAttr.when(context), true); + expect( + onLongPressAttr.value, + StyleMix(attribute1, attribute2, attribute3), + ); + expect(onLongPressAttr.variant.name, 'on-long-pressed'); + expect(onLongPressAttr.variant.when(context), true); + }); + + testWidgets('hover state', (tester) async { + await tester.pumpWithPressable( + Container(), + state: PressableState.hover, + focus: true, + ); + + final context = tester.element(find.byType(Container)); + + final onHoverAttr = onHover(attribute1, attribute2, attribute3); + + expect(onHoverAttr.when(context), true); + expect(onHoverAttr.value, StyleMix(attribute1, attribute2, attribute3)); + expect(onHoverAttr.variant.name, 'on-hover'); + expect(onHoverAttr.variant.when(context), true); + }); + + testWidgets('disabled state', (tester) async { + await tester.pumpWithPressable( + Container(), + state: PressableState.disabled, + focus: true, + ); + + final context = tester.element(find.byType(Container)); + + final onDisabledAttr = onDisabled(attribute1, attribute2, attribute3); + + expect(onDisabledAttr.when(context), true); + expect( + onDisabledAttr.value, + StyleMix(attribute1, attribute2, attribute3), + ); + expect(onDisabledAttr.variant.name, 'on-disabled'); + expect(onDisabledAttr.variant.when(context), true); + }); + + // onEnabled + testWidgets('enabled state', (tester) async { + await tester.pumpWithPressable( + Container(), + state: PressableState.pressed, + focus: true, + ); + + final context = tester.element(find.byType(Container)); + + final onEnabledAttr = onEnabled(attribute1, attribute2, attribute3); + + expect(onEnabledAttr.when(context), true); + expect( + onEnabledAttr.value, + StyleMix(attribute1, attribute2, attribute3), + ); + expect(onEnabledAttr.variant.name, 'not(on-disabled)'); + expect(onEnabledAttr.variant.when(context), true); + }); + + // onFocus + testWidgets('focus state', (tester) async { + await tester.pumpWithPressable( + Container(), + state: PressableState.pressed, + focus: true, + ); + + final context = tester.element(find.byType(Container)); + + final onFocusAttr = onFocus(attribute1, attribute2, attribute3); + + expect(onFocusAttr.when(context), true); + expect(onFocusAttr.value, StyleMix(attribute1, attribute2, attribute3)); + expect(onFocusAttr.variant.name, 'on-focus'); + expect(onFocusAttr.variant.when(context), true); + }); + }); +} diff --git a/test/src/utils/space_util_test.dart b/test/src/utils/space_util_test.dart new file mode 100644 index 000000000..6854b9013 --- /dev/null +++ b/test/src/utils/space_util_test.dart @@ -0,0 +1,548 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/mix.dart'; + +void main() { + group('Padding Utils', () { + test('padding()', () { + expect( + padding(10), + const PaddingAttribute(top: 10, bottom: 10, left: 10, right: 10), + ); + expect( + padding(10, 20), + const PaddingAttribute(top: 10, bottom: 10, left: 20, right: 20), + ); + expect( + padding(10, 20, 30), + const PaddingAttribute(top: 10, bottom: 30, left: 20, right: 20), + ); + expect( + padding(10, 20, 30, 40), + const PaddingAttribute(top: 10, bottom: 30, left: 40, right: 20), + ); + }); + + test('paddingDirectional()', () { + expect( + paddingDirectional(10), + const PaddingDirectionalAttribute( + start: 10, + end: 10, + top: 10, + bottom: 10, + ), + reason: '1', + ); + expect( + paddingDirectional(10, 20), + const PaddingDirectionalAttribute( + top: 10, + bottom: 10, + start: 20, + end: 20, + ), + reason: '2', + ); + expect( + paddingDirectional(10, 20, 30), + const PaddingDirectionalAttribute( + top: 10, + bottom: 30, + start: 20, + end: 20, + ), + reason: '3', + ); + expect( + paddingDirectional(10, 20, 30, 40), + const PaddingDirectionalAttribute( + top: 10, + end: 20, + bottom: 30, + start: 40, + ), + reason: '4', + ); + }); + + // paddingFrom + test('paddingFrom', () { + expect( + paddingFrom(const EdgeInsets.all(10)), + const PaddingAttribute(top: 10, bottom: 10, left: 10, right: 10), + reason: '1', + ); + + expect( + paddingFrom(const EdgeInsets.only(top: 10)), + const PaddingAttribute(top: 10, bottom: 0, left: 0, right: 0), + reason: '2', + ); + + expect( + paddingFrom(const EdgeInsets.only(left: 10)), + const PaddingAttribute(left: 10, bottom: 0, top: 0, right: 0), + reason: '3', + ); + + expect( + paddingFrom(const EdgeInsets.only(right: 10)), + const PaddingAttribute(right: 10, bottom: 0, top: 0, left: 0), + reason: '4', + ); + + expect( + paddingFrom(const EdgeInsets.only(bottom: 10)), + const PaddingAttribute(bottom: 10, top: 0, left: 0, right: 0), + reason: '5', + ); + + expect( + paddingFrom(const EdgeInsets.symmetric(horizontal: 10)), + const PaddingAttribute(left: 10, right: 10, top: 0, bottom: 0), + reason: '6', + ); + + expect( + paddingFrom(const EdgeInsets.symmetric(vertical: 10)), + const PaddingAttribute(top: 10, bottom: 10, left: 0, right: 0), + reason: '7', + ); + + expect( + paddingFrom(const EdgeInsetsDirectional.only(start: 10)), + const PaddingDirectionalAttribute(start: 10, end: 0, top: 0, bottom: 0), + reason: '8', + ); + + expect( + paddingFrom(const EdgeInsetsDirectional.only(end: 10)), + const PaddingDirectionalAttribute(end: 10, start: 0, top: 0, bottom: 0), + reason: '9', + ); + + expect( + paddingFrom(const EdgeInsetsDirectional.only(top: 10)), + const PaddingDirectionalAttribute(top: 10, bottom: 0, start: 0, end: 0), + reason: '10', + ); + + expect( + paddingFrom(const EdgeInsetsDirectional.only(bottom: 10)), + const PaddingDirectionalAttribute(bottom: 10, top: 0, start: 0, end: 0), + reason: '11', + ); + + expect( + paddingFrom(const EdgeInsetsDirectional.only(start: 10, end: 20)), + const PaddingDirectionalAttribute( + start: 10, + end: 20, + top: 0, + bottom: 0, + ), + reason: '12', + ); + + expect( + paddingFrom( + const EdgeInsetsDirectional.only(start: 10, end: 20, top: 30)), + const PaddingDirectionalAttribute( + start: 10, + end: 20, + top: 30, + bottom: 0, + ), + reason: '13', + ); + + expect( + paddingFrom( + const EdgeInsetsDirectional.only( + start: 10, + end: 20, + top: 30, + bottom: 40, + ), + ), + const PaddingDirectionalAttribute( + start: 10, + end: 20, + top: 30, + bottom: 40, + ), + reason: '14', + ); + }); + + // paddingDirectionalFrom + + test('paddingOnly', () { + expect( + paddingOnly(top: 10), + const PaddingAttribute(top: 10), + ); + + expect( + paddingOnly(left: 10), + const PaddingAttribute(left: 10), + ); + + expect( + paddingOnly(right: 10), + const PaddingAttribute(right: 10), + ); + + expect( + paddingOnly(bottom: 10), + const PaddingAttribute(bottom: 10), + ); + }); + + test('paddingTop', () { + expect( + paddingTop(10), + const PaddingAttribute(top: 10), + ); + }); + + test('paddingBottom', () { + expect( + paddingBottom(10), + const PaddingAttribute(bottom: 10), + ); + }); + + test('paddingLeft', () { + expect( + paddingLeft(10), + const PaddingAttribute(left: 10), + ); + }); + + test('paddingRight', () { + expect( + paddingRight(10), + const PaddingAttribute(right: 10), + ); + }); + + test('paddingStart', () { + expect( + paddingStart(10), + const PaddingDirectionalAttribute(start: 10), + ); + }); + + test('paddingEnd', () { + expect( + paddingEnd(10), + const PaddingDirectionalAttribute(end: 10), + ); + }); + + test('paddingHorizontal', () { + expect( + paddingHorizontal(10), + const PaddingAttribute(left: 10, right: 10), + ); + }); + + test('paddingVertical', () { + expect( + paddingVertical(10), + const PaddingAttribute(top: 10, bottom: 10), + ); + }); + + test('paddingAll', () { + expect( + paddingAll(10), + const PaddingAttribute(top: 10, bottom: 10, left: 10, right: 10), + ); + }); + + test('paddingDirectionalOnly', () { + expect( + paddingDirectionalOnly(start: 10), + const PaddingDirectionalAttribute(start: 10), + ); + + expect( + paddingDirectionalOnly(end: 10), + const PaddingDirectionalAttribute(end: 10), + ); + + expect( + paddingDirectionalOnly(start: 10, end: 20), + const PaddingDirectionalAttribute(start: 10, end: 20), + ); + + expect( + paddingDirectionalOnly(start: 10, end: 20, top: 30), + const PaddingDirectionalAttribute(start: 10, end: 20, top: 30), + ); + + expect( + paddingDirectionalOnly(start: 10, end: 20, top: 30, bottom: 40), + const PaddingDirectionalAttribute( + start: 10, end: 20, top: 30, bottom: 40), + ); + }); + }); + + group('Margin Utils', () { + test('margin()', () { + expect( + margin(10), + const MarginAttribute(top: 10, bottom: 10, left: 10, right: 10), + ); + expect( + margin(10, 20), + const MarginAttribute(top: 10, bottom: 10, left: 20, right: 20), + ); + expect( + margin(10, 20, 30), + const MarginAttribute(top: 10, bottom: 30, left: 20, right: 20), + ); + expect( + margin(10, 20, 30, 40), + const MarginAttribute(top: 10, bottom: 30, left: 40, right: 20), + ); + }); + + // marginDirectional() + test('marginDirectional()', () { + expect( + marginDirectional(10), + const MarginDirectionalAttribute( + start: 10, + end: 10, + top: 10, + bottom: 10, + ), + reason: '1', + ); + expect( + marginDirectional(10, 20), + const MarginDirectionalAttribute( + top: 10, + bottom: 10, + start: 20, + end: 20, + ), + reason: '2', + ); + expect( + marginDirectional(10, 20, 30), + const MarginDirectionalAttribute( + top: 10, + bottom: 30, + start: 20, + end: 20, + ), + reason: '3', + ); + expect( + marginDirectional(10, 20, 30, 40), + const MarginDirectionalAttribute( + top: 10, + end: 20, + bottom: 30, + start: 40, + ), + reason: '4', + ); + }); + + test('marginOnly', () { + expect( + marginOnly(top: 10), + const MarginAttribute(top: 10), + ); + + expect( + marginOnly(left: 10), + const MarginAttribute(left: 10), + ); + + expect( + marginOnly(right: 10), + const MarginAttribute(right: 10), + ); + + expect( + marginOnly(bottom: 10), + const MarginAttribute(bottom: 10), + ); + }); + + test('marginTop', () { + expect( + marginTop(10), + const MarginAttribute(top: 10), + ); + }); + + test('marginBottom', () { + expect( + marginBottom(10), + const MarginAttribute(bottom: 10), + ); + }); + + test('marginLeft', () { + expect( + marginLeft(10), + const MarginAttribute(left: 10), + ); + }); + + test('marginRight', () { + expect( + marginRight(10), + const MarginAttribute(right: 10), + ); + }); + + test('marginStart', () { + expect( + marginStart(10), + const MarginDirectionalAttribute(start: 10), + ); + }); + + test('marginEnd', () { + expect( + marginEnd(10), + const MarginDirectionalAttribute(end: 10), + ); + }); + + test('marginHorizontal', () { + expect( + marginHorizontal(10), + const MarginAttribute(left: 10, right: 10), + ); + }); + + test('marginVertical', () { + expect( + marginVertical(10), + const MarginAttribute(top: 10, bottom: 10), + ); + }); + + test('marginAll', () { + expect( + marginAll(10), + const MarginAttribute(top: 10, bottom: 10, left: 10, right: 10), + ); + }); + + test('marginFrom', () { + expect( + marginFrom(const EdgeInsets.all(10)), + const MarginAttribute(top: 10, bottom: 10, left: 10, right: 10), + ); + + expect( + marginFrom(const EdgeInsets.only(top: 10)), + const MarginAttribute(top: 10, bottom: 0, left: 0, right: 0), + ); + + expect( + marginFrom(const EdgeInsets.only(left: 10)), + const MarginAttribute(left: 10, bottom: 0, top: 0, right: 0), + ); + + expect( + marginFrom(const EdgeInsets.only(right: 10)), + const MarginAttribute(right: 10, bottom: 0, top: 0, left: 0), + ); + + expect( + marginFrom(const EdgeInsets.only(bottom: 10)), + const MarginAttribute(bottom: 10, top: 0, left: 0, right: 0), + ); + + expect( + marginFrom(const EdgeInsets.symmetric(horizontal: 10)), + const MarginAttribute(left: 10, right: 10, top: 0, bottom: 0), + ); + + expect( + marginFrom(const EdgeInsets.symmetric(vertical: 10)), + const MarginAttribute(top: 10, bottom: 10, left: 0, right: 0), + ); + + expect( + marginFrom(const EdgeInsetsDirectional.only(start: 10)), + const MarginDirectionalAttribute(start: 10, end: 0, top: 0, bottom: 0), + ); + + expect( + marginFrom(const EdgeInsetsDirectional.only(end: 10)), + const MarginDirectionalAttribute(end: 10, start: 0, top: 0, bottom: 0), + ); + + expect( + marginFrom(const EdgeInsetsDirectional.only(top: 10)), + const MarginDirectionalAttribute(top: 10, bottom: 0, start: 0, end: 0), + ); + + expect( + marginFrom(const EdgeInsetsDirectional.only(bottom: 10)), + const MarginDirectionalAttribute(bottom: 10, top: 0, start: 0, end: 0), + ); + + expect( + marginFrom(const EdgeInsetsDirectional.only(start: 10, end: 20)), + const MarginDirectionalAttribute(start: 10, end: 20, top: 0, bottom: 0), + ); + + expect( + marginFrom( + const EdgeInsetsDirectional.only(start: 10, end: 20, top: 30)), + const MarginDirectionalAttribute( + start: 10, end: 20, top: 30, bottom: 0), + ); + + expect( + marginFrom(const EdgeInsetsDirectional.only( + start: 10, end: 20, top: 30, bottom: 40)), + const MarginDirectionalAttribute( + start: 10, end: 20, top: 30, bottom: 40), + ); + }); + + test('marginDirectionalOnly', () { + expect( + marginDirectionalOnly(start: 10), + const MarginDirectionalAttribute(start: 10), + ); + + expect( + marginDirectionalOnly(end: 10), + const MarginDirectionalAttribute(end: 10), + ); + + expect( + marginDirectionalOnly(start: 10, end: 20), + const MarginDirectionalAttribute(start: 10, end: 20), + ); + + expect( + marginDirectionalOnly(start: 10, end: 20, top: 30), + const MarginDirectionalAttribute(start: 10, end: 20, top: 30), + ); + + expect( + marginDirectionalOnly(start: 10, end: 20, top: 30, bottom: 40), + const MarginDirectionalAttribute( + start: 10, end: 20, top: 30, bottom: 40), + ); + }); + }); +} diff --git a/test/src/utils/text_util_test.dart b/test/src/utils/text_util_test.dart new file mode 100644 index 000000000..5eb5e4a9f --- /dev/null +++ b/test/src/utils/text_util_test.dart @@ -0,0 +1,89 @@ +// Import necessary packages +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/mix.dart'; + +void main() { + group('TextStyleAttribute', () { + test('textStyle creates TextStyleAttribute correctly', () { + final yellowPaint = Paint()..color = Colors.yellow; + final purplePaint = Paint()..color = Colors.purple; + final textStyleAttribute = textStyle( + fontFamily: 'Roboto', + fontWeight: FontWeight.bold, + fontStyle: FontStyle.italic, + fontSize: 16.0, + letterSpacing: 1.0, + wordSpacing: 2.0, + textBaseline: TextBaseline.ideographic, + shadows: [ + const Shadow( + blurRadius: 1.0, + color: Colors.black, + offset: Offset(1.0, 1.0), + ), + ], + color: Colors.red, + backgroundColor: Colors.blue, + fontFeatures: [const FontFeature.alternative(4)], + decoration: TextDecoration.underline, + decorationColor: Colors.green, + decorationStyle: TextDecorationStyle.dashed, + foreground: yellowPaint, + background: purplePaint, + debugLabel: 'debugLabel', + locale: const Locale('en', 'US'), + height: 2.0, + ); + + expect(textStyleAttribute.fontWeight, FontWeight.bold); + expect(textStyleAttribute.fontStyle, FontStyle.italic); + expect(textStyleAttribute.fontSize, 16.0); + expect(textStyleAttribute.letterSpacing, 1.0); + expect(textStyleAttribute.wordSpacing, 2.0); + expect(textStyleAttribute.textBaseline, TextBaseline.ideographic); + expect(textStyleAttribute.shadows?.length, 1); + expect(textStyleAttribute.shadows?.first.blurRadius, 1.0); + expect(textStyleAttribute.shadows?.first.color?.value, Colors.black); + expect(textStyleAttribute.shadows?.first.offset, const Offset(1.0, 1.0)); + expect(textStyleAttribute.color?.value, Colors.red); + expect(textStyleAttribute.backgroundColor?.value, Colors.blue); + expect(textStyleAttribute.fontFeatures?.length, 1); + expect( + textStyleAttribute.fontFeatures?.first, + const FontFeature.alternative(4), + ); + expect(textStyleAttribute.decoration, TextDecoration.underline); + expect(textStyleAttribute.decorationColor?.value, Colors.green); + expect(textStyleAttribute.decorationStyle, TextDecorationStyle.dashed); + expect(textStyleAttribute.foreground, yellowPaint); + expect(textStyleAttribute.background, purplePaint); + expect(textStyleAttribute.debugLabel, 'debugLabel'); + expect(textStyleAttribute.locale, const Locale('en', 'US')); + expect(textStyleAttribute.height, 2.0); + }); + + test('bold returns TextStyleAttribute with FontWeight.bold', () { + final textStyleAttribute = bold(); + + expect(textStyleAttribute.fontWeight, FontWeight.bold); + }); + + test('italic returns TextStyleAttribute with FontStyle.italic', () { + final textStyleAttribute = italic(); + + expect(textStyleAttribute.fontStyle, FontStyle.italic); + }); + + // textDirective + test('textDirective returns TextStyleAttribute with TextDirective', () { + final textStyleAttribute = textDirective(const UppercaseDirective()); + + expect(textStyleAttribute.value, [const UppercaseDirective()]); + expect(textStyleAttribute.value.first, const UppercaseDirective()); + expect(textStyleAttribute.value.first.runtimeType, UppercaseDirective); + }); + }); +} diff --git a/test/src/variants/multi_variant_test.dart b/test/src/variants/multi_variant_test.dart new file mode 100644 index 000000000..3484aa01f --- /dev/null +++ b/test/src/variants/multi_variant_test.dart @@ -0,0 +1,58 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/mix.dart'; +import 'package:mix/src/variants/multi_variant.dart'; + +import '../../helpers/testing_utils.dart'; + +void main() { + group('MultiVariant', () { + test('remove should remove the correct variants', () { + const variant1 = Variant('variant1'); + const variant2 = Variant('variant2'); + const variant3 = Variant('variant3'); + final multiVariant = + MultiVariant.and(const [variant1, variant2, variant3]); + + final result = multiVariant.remove([variant1, variant2]); + + expect(result, isA()); + expect((result).name, variant3.name); + }); + + test('matches should correctly match variants', () { + const variant1 = Variant('variant1'); + const variant2 = Variant('variant2'); + const variant3 = Variant('variant3'); + final multiVariant = MultiVariant.and(const [variant1, variant2]); + + expect(multiVariant.matches([variant1, variant2, variant3]), isTrue); + expect(multiVariant.matches([variant1]), isFalse); + }); + + test('when should correctly match context variants', () { + final variant1 = ContextVariant('variant1', when: (context) => true); + final variant2 = ContextVariant('variant2', when: (context) => false); + final multiVariant = MultiVariant.and([variant1, variant2]); + + expect(multiVariant.when(MockBuildContext()), isFalse); + }); + + test('MultiVariant.and should correctly create a MultiVariant', () { + const variant1 = Variant('variant1'); + const variant2 = Variant('variant2'); + final multiVariant = MultiVariant.and(const [variant1, variant2]); + + expect(multiVariant.variants, containsAll([variant1, variant2])); + expect(multiVariant.type, MultiVariantType.and); + }); + + test('MultiVariant.or should correctly create a MultiVariant', () { + const variant1 = Variant('variant1'); + const variant2 = Variant('variant2'); + final multiVariant = MultiVariant.or(const [variant1, variant2]); + + expect(multiVariant.variants, containsAll([variant1, variant2])); + expect(multiVariant.type, MultiVariantType.or); + }); + }); +} diff --git a/test/src/variants/variant_operation_test.dart b/test/src/variants/variant_operation_test.dart new file mode 100644 index 000000000..bf3909963 --- /dev/null +++ b/test/src/variants/variant_operation_test.dart @@ -0,0 +1,20 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/mix.dart'; + +void main() { + group('VariantOperation', () { + test('should add variant with & operator', () { + const variant = Variant('test'); + const otherVariant = Variant('other'); + final result = otherVariant & variant; + expect(result.variants, contains(variant)); + }); + + test('should add variant with | operator', () { + const variant = Variant('test'); + const otherVariant = Variant('other'); + final result = otherVariant | variant; + expect(result.variants, contains(variant)); + }); + }); +} diff --git a/test/src/widgets/container_widget_test.dart b/test/src/widgets/container_widget_test.dart new file mode 100644 index 000000000..a79ac7211 --- /dev/null +++ b/test/src/widgets/container_widget_test.dart @@ -0,0 +1,53 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/mix.dart'; + +import '../../helpers/testing_utils.dart'; + +void main() { + testWidgets('StyledContainer', (WidgetTester tester) async { + final paddingAttr = padding(10); + final marginAttr = margin(10); + final backgroundColorAttr = backgroundColor(Colors.red); + final alignmentAttr = alignmentCenter(); + final clipAttr = clip(Clip.hardEdge); + + final boxDecorationAttr = boxDecoration( + border: border(color: Colors.red, width: 1, style: BorderStyle.solid), + borderRadius: borderRadius( + const Radius.circular(10), + ), + color: const ColorAttribute(Colors.red), + ); + + await tester.pumpStyledWidget( + StyledContainer( + style: StyleMix( + paddingAttr, + marginAttr, + backgroundColorAttr, + alignmentAttr, + clipAttr, + boxDecorationAttr, + ), + ), + ); + + final containerFinder = find.byType(Container); + Container containerWidget = tester.widget(containerFinder); + + final containerDecoration = containerWidget.decoration as BoxDecoration; + + final resolvedDecoration = boxDecorationAttr.resolve(EmptyMixData); + + expect(containerFinder, findsOneWidget); + expect(containerWidget.margin, marginAttr.resolve(EmptyMixData)); + expect(containerWidget.padding, paddingAttr.resolve(EmptyMixData)); + expect(containerWidget.clipBehavior, clipAttr.resolve(EmptyMixData)); + expect(containerWidget.alignment, alignmentAttr.resolve(EmptyMixData)); + expect(containerWidget.clipBehavior, clipAttr.resolve(EmptyMixData)); + expect(containerDecoration.border, resolvedDecoration.border); + expect(containerDecoration.color, resolvedDecoration.color); + expect(containerDecoration.borderRadius, resolvedDecoration.borderRadius); + }); +} diff --git a/test/src/widgets/pressable/pressable.notifier_test.dart b/test/src/widgets/pressable/pressable.notifier_test.dart new file mode 100644 index 000000000..2d2f39cc9 --- /dev/null +++ b/test/src/widgets/pressable/pressable.notifier_test.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/mix.dart'; + +import '../../../helpers/testing_utils.dart'; + +void main() { + group('PressableNotifier', () { + test('constructor', () { + final notifier = PressableNotifier( + state: PressableState.pressed, + focus: true, + child: Container(), + ); + + expect(notifier.state, PressableState.pressed); + expect(notifier.focus, true); + expect(notifier.child, isA()); + }); + + test('of', () { + final notifier = PressableNotifier( + state: PressableState.pressed, + focus: true, + child: Container(), + ); + + final otherNotifier = PressableNotifier( + state: PressableState.hover, + focus: false, + child: Container(), + ); + + final sameNotifier = PressableNotifier( + focus: true, + state: PressableState.pressed, + child: Container(), + ); + + expect(notifier.updateShouldNotify(otherNotifier), true); + expect(notifier.updateShouldNotify(sameNotifier), false); + expect(PressableNotifier.of(MockBuildContext()), null); + }); + + testWidgets('can get it from context', (tester) async { + await tester.pumpWithPressable( + Container(), + state: PressableState.pressed, + focus: true, + ); + + final context = tester.element(find.byType(Container)); + + final notifier = PressableNotifier.of(context); + + expect(notifier, isA()); + expect(notifier!.state, PressableState.pressed); + expect(notifier.focus, true); + }); + }); +} diff --git a/test/src/widgets/pressable/pressable_widget_test.dart b/test/src/widgets/pressable/pressable_widget_test.dart new file mode 100644 index 000000000..518977c8f --- /dev/null +++ b/test/src/widgets/pressable/pressable_widget_test.dart @@ -0,0 +1,45 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/mix.dart'; + +import '../../../helpers/testing_utils.dart'; + +void main() { + const attribute1 = MockIntScalarAttribute(1); + const attribute2 = MockStringScalarAttribute('attribute2'); + const attribute3 = MockBooleanScalarAttribute(true); + + testWidgets('Pressable', (tester) async { + final firstKey = UniqueKey(); + final secondKey = UniqueKey(); + await tester.pumpWidget(Column( + children: [ + Pressable( + onPressed: () {}, + child: Container( + key: firstKey, + ), + ), + Pressable( + onPressed: null, + child: Container( + key: secondKey, + ), + ), + ], + )); + + final onEnabledAttr = onEnabled(attribute1, attribute2, attribute3); + + final firstContext = tester.element(find.byKey(firstKey)); + final secondContext = tester.element(find.byKey(secondKey)); + + final firstNotifier = PressableNotifier.of(firstContext); + final secondNotifier = PressableNotifier.of(secondContext); + + expect(onEnabledAttr.when(firstContext), true); + expect(firstNotifier!.state, PressableState.inactive); + expect(onEnabledAttr.when(secondContext), false); + expect(secondNotifier!.state, PressableState.disabled); + }); +} diff --git a/test/src/widgets/stack_widget_test.dart b/test/src/widgets/stack_widget_test.dart new file mode 100644 index 000000000..4b7f7f7cc --- /dev/null +++ b/test/src/widgets/stack_widget_test.dart @@ -0,0 +1,125 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mix/mix.dart'; + +import '../../helpers/testing_utils.dart'; + +// import '../specs/stack_spec.dart'; +// import 'container_widget.dart'; +// import 'styled_widget.dart'; + +// class StyledStack extends StyledWidget { +// const StyledStack({ +// this.children = const [], +// super.inherit, +// super.key, +// super.style, +// }); + +// final List children; + +// @override +// Widget build(BuildContext context) { +// return buildWithStyle(context, (data) { +// final spec = StackSpec.resolve(data); + +// const fallback = Stack(); + +// return Stack( +// alignment: spec.alignment ?? fallback.alignment, +// fit: spec.fit ?? fallback.fit, +// clipBehavior: spec.clipBehavior ?? fallback.clipBehavior, +// children: children, +// ); +// }); +// } +// } + +// class ZBox extends StyledWidget { +// const ZBox({ +// this.children = const [], +// super.inherit, +// super.key, +// super.style, +// }); + +// final List children; + +// @override +// Widget build(BuildContext context) { +// return buildWithStyle(context, (data) { +// return StyledContainer( +// inherit: true, +// child: StyledStack(inherit: true, children: children), +// ); +// }); +// } +// } + +void main() { + testWidgets('Stack', (tester) async { + final style = StyleMix( + stackFit(StackFit.expand), + alignmentTopCenter(), + clip(Clip.antiAlias), + textDirection(TextDirection.ltr), + ); + await tester.pumpMaterialApp( + StyledStack( + style: style, + children: [ + Container( + height: 100, + width: 100, + color: const Color(0xFF000000), + ), + Container( + height: 50, + width: 50, + color: const Color(0xFF0000FF), + ), + ], + ), + ); + + final stack = tester.widget(find.byType(Stack)); + + expect(find.byType(Stack), findsOneWidget); + expect(find.byType(Container), findsNWidgets(2)); + expect(stack.alignment, Alignment.topCenter); + expect(stack.fit, StackFit.expand); + expect(stack.clipBehavior, Clip.antiAlias); + expect(stack.textDirection, TextDirection.ltr); + }); + + testWidgets('ZBox', (tester) async { + final style = StyleMix( + stackFit(StackFit.expand), + alignmentTopCenter(), + clip(Clip.antiAlias), + textDirection(TextDirection.ltr), + backgroundColor(Colors.red), + ); + + await tester.pumpMaterialApp( + ZBox( + style: style, + children: const [], + ), + ); + + final stack = tester.widget(find.byType(Stack)); + final container = tester.widget(find.byType(Container)); + + expect(find.byType(Stack), findsOneWidget); + + expect(find.byType(StyledContainer), findsOneWidget); + + expect((container.decoration as BoxDecoration).color, Colors.red); + + expect(stack.alignment, Alignment.topCenter); + expect(stack.fit, StackFit.expand); + expect(stack.clipBehavior, Clip.antiAlias); + expect(stack.textDirection, TextDirection.ltr); + }); +} diff --git a/test/variants/variants_test.dart b/test/variants/variants_test.dart deleted file mode 100644 index 70ca1c7ad..000000000 --- a/test/variants/variants_test.dart +++ /dev/null @@ -1,379 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:mix/mix.dart'; - -void main() { - testWidgets('System Theme Variants', (tester) async { - final style = StyleMix( - backgroundColor(Colors.green), - onDark(backgroundColor(Colors.black)), - height(50), - width(50), - ); - - await tester.pumpWidget( - MaterialApp( - theme: ThemeData.dark(), - home: StyledContainer( - style: style, - ), - ), - ); - final containerWidget = - find.byType(Container).evaluate().first.widget as Container; - - final widgetFinder = find.byType(MixedContainer); - - // Get BuildContext for boxWidget - BuildContext context = tester.element(widgetFinder); - - expect(context.brightness, Brightness.dark); - expect(containerWidget.color, isNot(equals(Colors.green))); - expect(containerWidget.color, Colors.black); - }); - - testWidgets('not Variant', (tester) async { - await tester.pumpWidget(MaterialApp( - theme: ThemeData(), - darkTheme: ThemeData.dark(), - themeMode: ThemeMode.light, - home: StyledContainer( - style: StyleMix( - onNot(onDark)(backgroundColor(Colors.black)), - height(50), - width(50), - ), - ), - )); - - final colorWidget = tester.widget(find.byType(Container)); - expect(colorWidget.color, Colors.black); - }); - - testWidgets('Variant onDark light', (tester) async { - await tester.pumpWidget(MaterialApp( - theme: ThemeData(), - darkTheme: ThemeData.dark(), - themeMode: ThemeMode.light, - home: StyledContainer( - style: StyleMix( - onDark(backgroundColor(Colors.teal)), - backgroundColor(Colors.red), - ), - ), - )); - - final colorWidget = tester.widget(find.byType(Container)); - expect(colorWidget.color, isNot(equals(Colors.black))); - }); - - testWidgets('Variant onDark dark', (tester) async { - await tester.pumpWidget(MaterialApp( - theme: ThemeData(), - darkTheme: ThemeData.dark(), - themeMode: ThemeMode.dark, - home: StyledContainer( - style: StyleMix( - onDark(backgroundColor(Colors.teal)), - backgroundColor(Colors.red), - ), - ), - )); - - final colorWidget = tester.widget(find.byType(Container)); - expect(colorWidget.color, Colors.teal); - }); - - testWidgets('Variant onHover', (tester) async { - await tester.pumpWidget(MaterialApp( - theme: ThemeData(), - darkTheme: ThemeData.dark(), - themeMode: ThemeMode.dark, - home: Pressable( - onPressed: () {}, - child: StyledContainer( - style: StyleMix( - onHover(backgroundColor(Colors.teal)), - backgroundColor(Colors.red), - ), - ), - ), - )); - - final colorWidget = tester.widget(find.byType(Container)); - expect(colorWidget.color, Colors.red); - - // TODO: Figure out how to simulate hover - }); - - testWidgets('Variant onXSmall', (tester) async { - await tester.pumpWidget( - MediaQuery( - data: const MediaQueryData(size: Size(1000, 1000)), - child: StyledContainer( - style: StyleMix( - onXSmall(backgroundColor(Colors.teal)), - backgroundColor(Colors.red), - ), - ), - ), - ); - - expect(find.byType(Container), findsOneWidget); - expect(tester.widget(find.byType(Container)).color, Colors.red); - - // Set screen size to xsmall - await tester.pumpWidget( - MediaQuery( - data: const MediaQueryData(size: Size(100, 100)), - child: StyledContainer( - style: StyleMix( - onXSmall(backgroundColor(Colors.teal)), - backgroundColor(Colors.red), - ), - ), - ), - ); - - expect(find.byType(Container), findsOneWidget); - expect(tester.widget(find.byType(Container)).color, Colors.teal); - }); - - testWidgets('Variant onSmall', (tester) async { - await tester.pumpWidget( - MediaQuery( - data: const MediaQueryData(size: Size(3000, 3000)), - child: StyledContainer( - style: StyleMix( - onSmall(backgroundColor(Colors.teal)), - backgroundColor(Colors.red), - ), - ), - ), - ); - - expect(find.byType(Container), findsOneWidget); - expect(tester.widget(find.byType(Container)).color, Colors.red); - // Set screen size to small - await tester.pumpWidget( - MediaQuery( - data: const MediaQueryData(size: Size(300, 300)), - child: StyledContainer( - style: StyleMix( - onSmall(backgroundColor(Colors.teal)), - backgroundColor(Colors.red), - ), - ), - ), - ); - - expect(find.byType(Container), findsOneWidget); - expect(tester.widget(find.byType(Container)).color, Colors.teal); - }); - - testWidgets('Variant onMedium', (tester) async { - // Set screen size to medium - await tester.pumpWidget( - MediaQuery( - data: const MediaQueryData(size: Size(3000, 3000)), - child: StyledContainer( - style: StyleMix( - onMedium(backgroundColor(Colors.teal)), - backgroundColor(Colors.red), - ), - ), - ), - ); - - expect(find.byType(Container), findsOneWidget); - expect(tester.widget(find.byType(Container)).color, Colors.red); - - // Set screen size to medium - await tester.pumpWidget( - MediaQuery( - data: const MediaQueryData(size: Size(1300, 1300)), - child: StyledContainer( - style: StyleMix( - onMedium(backgroundColor(Colors.teal)), - backgroundColor(Colors.red), - ), - ), - ), - ); - - expect(find.byType(Container), findsOneWidget); - expect(tester.widget(find.byType(Container)).color, Colors.teal); - }); - - testWidgets('Variant onLarge', (tester) async { - // Set screen size to large - await tester.pumpWidget( - MediaQuery( - data: const MediaQueryData(size: Size(3000, 3000)), - child: StyledContainer( - style: StyleMix( - onLarge(backgroundColor(Colors.teal)), - backgroundColor(Colors.red), - ), - ), - ), - ); - - expect(find.byType(Container), findsOneWidget); - expect(tester.widget(find.byType(Container)).color, Colors.teal); - - // Set screen size to large - await tester.pumpWidget( - MediaQuery( - data: const MediaQueryData(size: Size(2000, 2000)), - child: StyledContainer( - style: StyleMix( - onLarge(backgroundColor(Colors.teal)), - backgroundColor(Colors.red), - ), - ), - ), - ); - - expect(find.byType(Container), findsOneWidget); - expect(tester.widget(find.byType(Container)).color, Colors.teal); - }); - - testWidgets('Variant onPortrait', (tester) async { - // Set screen size to portrait - await tester.pumpWidget( - MediaQuery( - data: const MediaQueryData(size: Size(2000, 1000)), - child: StyledContainer( - style: StyleMix( - onPortrait(backgroundColor(Colors.teal)), - backgroundColor(Colors.red), - ), - ), - ), - ); - - expect(find.byType(Container), findsOneWidget); - expect(tester.widget(find.byType(Container)).color, Colors.red); - - // Set screen size to portrait - await tester.pumpWidget( - MediaQuery( - data: const MediaQueryData(size: Size(1000, 2000)), - child: StyledContainer( - style: StyleMix( - onPortrait(backgroundColor(Colors.teal)), - backgroundColor(Colors.red), - ), - ), - ), - ); - - expect(find.byType(Container), findsOneWidget); - expect(tester.widget(find.byType(Container)).color, Colors.teal); - }); - - testWidgets('Variant onLandscape', (tester) async { - // Set screen size to landscape - await tester.pumpWidget( - MediaQuery( - data: const MediaQueryData(size: Size(2000, 1000)), - child: StyledContainer( - style: StyleMix( - onLandscape(backgroundColor(Colors.teal)), - backgroundColor(Colors.red), - ), - ), - ), - ); - - expect(find.byType(Container), findsOneWidget); - expect(tester.widget(find.byType(Container)).color, Colors.teal); - - // Set screen size to landscape - await tester.pumpWidget( - MediaQuery( - data: const MediaQueryData(size: Size(1000, 2000)), - child: StyledContainer( - style: StyleMix( - onLandscape(backgroundColor(Colors.teal)), - backgroundColor(Colors.red), - ), - ), - ), - ); - - expect(find.byType(Container), findsOneWidget); - expect(tester.widget(find.byType(Container)).color, Colors.red); - }); - - testWidgets('Variant onRTL', (tester) async { - // Set screen size to RTL - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.rtl, - child: StyledContainer( - style: StyleMix( - onRTL(backgroundColor(Colors.teal)), - backgroundColor(Colors.red), - ), - ), - ), - ); - - expect(find.byType(Container), findsOneWidget); - expect(tester.widget(find.byType(Container)).color, Colors.teal); - - // Set screen size to RTL - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: StyledContainer( - style: StyleMix( - onRTL(backgroundColor(Colors.teal)), - backgroundColor(Colors.red), - ), - ), - ), - ); - - expect(find.byType(Container), findsOneWidget); - expect(tester.widget(find.byType(Container)).color, Colors.red); - }); - - testWidgets('Variant onLTR', (tester) async { - // Set screen size to LTR - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: StyledContainer( - style: StyleMix( - onLTR(backgroundColor(Colors.teal)), - backgroundColor(Colors.red), - ), - ), - ), - ); - - expect(find.byType(Container), findsOneWidget); - expect(tester.widget(find.byType(Container)).color, Colors.teal); - - // Set screen size to LTR - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.rtl, - child: StyledContainer( - style: StyleMix( - onLTR(backgroundColor(Colors.teal)), - backgroundColor(Colors.red), - ), - ), - ), - ); - - expect(find.byType(Container), findsOneWidget); - expect(tester.widget(find.byType(Container)).color, Colors.red); - }); - - // TODO: Figure out how to test enabed/disabled -} diff --git a/test/widgets/box_test.dart b/test/widgets/box_test.dart deleted file mode 100644 index 2029ed8bb..000000000 --- a/test/widgets/box_test.dart +++ /dev/null @@ -1,325 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:mix/src/attributes/shared/shared.attributes.dart'; -import 'package:mix/src/decorators/decorators_utilities.dart'; -import 'package:mix/src/dtos/border/border.dto.dart'; -import 'package:mix/src/dtos/color.dto.dart'; -import 'package:mix/src/dtos/edge_insets/edge_insets.dto.dart'; -import 'package:mix/src/dtos/radius/border_radius.dto.dart'; -import 'package:mix/src/dtos/radius/radius_dto.dart'; -import 'package:mix/src/extensions/style_mix_ext.dart'; -import 'package:mix/src/factory/style_mix.dart'; -import 'package:mix/src/widgets/container/container.attributes.dart'; -import 'package:mix/src/widgets/container/container.utilities.dart'; -import 'package:mix/src/widgets/container/container.widget.dart'; - -import '../helpers/testing_utils.dart'; - -void main() { - group( - "Mix Box widget", - () { - const widgetText = 'This is a Box Widget'; - - testWidgets( - 'Adds child on widget', - (tester) async { - await tester.pumpWidget( - TestMixWidget( - child: StyleMix().box( - child: const Text( - widgetText, - key: Key('child-key'), - ), - ), - ), - ); - - expect( - tester - .widget(find.byType(StyledContainer)) - .child - ?.key, - const Key('child-key'), - ); - - expect( - tester.widget(find.byType(Text)).data, - widgetText, - ); - }, - ); - - testWidgets( - 'Responds to Flexible attributes', - (tester) async { - await tester.pumpWidget( - BoxInsideFlexWidget( - StyleMix( - DecoratorUtility.flex(2), - DecoratorUtility.flexFit(FlexFit.tight), - ), - ), - ); - - final flexibleWidget = tester.widget( - find.byType(Flexible), - ); - - expect(flexibleWidget.flex, 2); - expect(flexibleWidget.fit, FlexFit.tight); - }, - ); - - testWidgets( - 'Responds to RotatedBox attributes', - (tester) async { - await tester.pumpWidget( - BoxTestWidget( - StyleMix( - DecoratorUtility.rotate(3), - ), - ), - ); - - final rotatedBoxWidget = tester.widget( - find.byType(RotatedBox), - ); - - expect(rotatedBoxWidget.quarterTurns, 3); - }, - ); - - testWidgets( - 'Responds to Hidden attributes', - (tester) async { - await tester.pumpWidget( - BoxTestWidget( - StyleMix(const SharedStyleAttributes(visible: false)), - ), - ); - - final hiddenWidget = tester.widget( - find.byType(SizedBox), - ); - - expect(hiddenWidget.height, 0.0); - expect(hiddenWidget.width, 0.0); - }, - ); - - testWidgets( - 'Responds to AspectRatio attributes', - (tester) async { - await tester.pumpWidget( - BoxTestWidget( - StyleMix(DecoratorUtility.aspectRatio(3 / 2)), - ), - ); - - final aspectRatioWidget = tester.widget( - find.byType(AspectRatio), - ); - - expect(aspectRatioWidget.aspectRatio, 1.5); - }, - ); - - testWidgets( - 'Responds to Align attributes', - (tester) async { - await tester.pumpWidget( - BoxTestWidget( - StyleMix( - const StyledContainerAttributes( - alignment: Alignment.centerRight, - ), - ), - ), - ); - - final alignWidget = tester.widget( - find.byType(Align), - ); - - expect(alignWidget.alignment, Alignment.centerRight); - }, - ); - - testWidgets( - 'Responds to Opacity attributes', - (tester) async { - await tester.pumpWidget( - BoxTestWidget( - StyleMix( - DecoratorUtility.opacity(0.5), - ), - ), - ); - - final opacityWidget = tester.widget( - find.byType(Opacity), - ); - - expect(opacityWidget.opacity, 0.5); - }, - ); - - testWidgets( - 'Responds to ColoredBox attributes', - (tester) async { - await tester.pumpWidget( - BoxTestWidget( - StyleMix(ContainerStyleUtilities().backgroundColor(Colors.lime)), - ), - ); - - final coloredBoxWidget = tester.widget( - find.byType(ColoredBox), - ); - - expect(coloredBoxWidget.color, Colors.lime); - }, - ); - - testWidgets( - 'Responds to Decoration attributes', - (tester) async { - final borderProps = BorderDto.all( - color: const ColorDto(Colors.green), - width: 1.0, - style: BorderStyle.solid, - ); - - final border = Border.all( - color: Colors.green, - width: 1.0, - style: BorderStyle.solid, - ); - const borderRadiusProps = BorderRadiusDto.only( - topLeft: RadiusDto.circular(20), - ); - const borderRadius = BorderRadius.only( - topLeft: Radius.circular(20), - ); - await tester.pumpWidget( - BoxTestWidget( - StyleMix( - const StyledContainerAttributes(color: ColorDto(Colors.purple)), - const StyledContainerAttributes( - borderRadius: borderRadiusProps,), - StyledContainerAttributes(border: borderProps), - ), - ), - ); - - final decoratedBoxWidget = tester.widget( - find.byType(Container), - ); - - final widgetDecoration = - decoratedBoxWidget.decoration as BoxDecoration; - - final decoration = BoxDecoration( - color: Colors.purple, - borderRadius: borderRadius, - border: border, - ); - expect(widgetDecoration.color, decoration.color); - expect(widgetDecoration.borderRadius, decoration.borderRadius); - expect(widgetDecoration.border, decoration.border); - // expect(widgetDecoration, decoration); - }, - ); - - testWidgets( - 'Responds to Margin attributes', - (tester) async { - const edgeInsets = EdgeInsets.only( - left: 15, - top: 25, - right: 35, - bottom: 45, - ); - - await tester.pumpWidget( - BoxTestWidget( - StyleMix( - StyledContainerAttributes( - margin: EdgeInsetsDto.from(edgeInsets), - ), - ), - ), - ); - - final marginWidget = tester.widget( - find.byType(Padding).first, - ); - - expect( - marginWidget.padding, - edgeInsets, - ); - }, - ); - - testWidgets( - 'Responds to Padding attributes', - (tester) async { - const edgeInsets = EdgeInsets.only( - left: 10, - top: 20, - right: 30, - bottom: 40, - ); - - await tester.pumpWidget( - BoxTestWidget( - StyleMix( - StyledContainerAttributes( - padding: EdgeInsetsDto.from(edgeInsets), - ), - ), - ), - ); - - final paddingWidget = tester.widget( - find.byType(Padding).first, - ); - - expect( - paddingWidget.padding, - const EdgeInsets.fromLTRB(10, 20, 30, 40), - ); - }, - ); - - testWidgets( - 'Responds to max/min constraints', - (tester) async { - await tester.pumpWidget( - BoxTestWidget( - StyleMix( - const StyledContainerAttributes(maxHeight: 105), - const StyledContainerAttributes(minHeight: 55), - const StyledContainerAttributes(maxWidth: 155), - const StyledContainerAttributes(minWidth: 45), - ), - ), - ); - - final container = tester.widget( - find.byType(Container), - ); - - final constraints = container.constraints; - - expect(constraints!.maxHeight, 105.0); - expect(constraints.minHeight, 55.0); - expect(constraints.maxWidth, 155.0); - expect(constraints.minWidth, 45.0); - }, - ); - }, - ); -} diff --git a/test/widgets/icon_test.dart b/test/widgets/icon_test.dart deleted file mode 100644 index d4b1871f1..000000000 --- a/test/widgets/icon_test.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:mix/src/attributes/shared/shared.attributes.dart'; -import 'package:mix/src/dtos/color.dto.dart'; -import 'package:mix/src/extensions/style_mix_ext.dart'; -import 'package:mix/src/factory/style_mix.dart'; -import 'package:mix/src/widgets/icon/icon.attributes.dart'; - -import '../helpers/testing_utils.dart'; - -void main() { - group("Mix Icon widget", () { - testWidgets('Adds icon on widget', (tester) async { - await tester.pumpWidget( - TestMixWidget( - child: StyleMix().icon(Icons.bolt), - ), - ); - - expect( - tester.widget(find.byType(Icon)).icon, - Icons.bolt, - ); - }); - - testWidgets('Adds Icon properties on widget', (tester) async { - await tester.pumpWidget( - TestMixWidget( - child: StyleMix( - const StyledIconAttributes(color: ColorDto(Colors.greenAccent)), - const StyledIconAttributes(size: 23), - const SharedStyleAttributes(textDirection: TextDirection.rtl), - ).icon(Icons.bolt), - ), - ); - - final iconProp = tester.widget(find.byType(Icon)); - - expect(iconProp.color, Colors.greenAccent); - expect(iconProp.size, 23); - expect(iconProp.icon, Icons.bolt); - - expect(iconProp.textDirection, TextDirection.rtl); - }); - }); -} diff --git a/test/widgets/text_test.dart b/test/widgets/text_test.dart deleted file mode 100644 index 9ff54cc5f..000000000 --- a/test/widgets/text_test.dart +++ /dev/null @@ -1,232 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:mix/mix.dart'; -import 'package:mix/src/widgets/text/text_directives/text_directives.dart'; - -import '../helpers/testing_utils.dart'; - -void main() { - group("Mix Text widget", () { - const widgetText = 'Mix Text Widget'; - testWidgets('Adds text on widget', (tester) async { - await tester.pumpWidget( - TestMixWidget( - child: StyleMix().text(widgetText), - ), - ); - - expect( - tester.widget(find.byType(Text)).data, - widgetText, - ); - }); - - testWidgets('Adds Text properties on widget', (tester) async { - await tester.pumpWidget( - TestMixWidget( - child: StyleMix( - TextUtility.overflow(TextOverflow.ellipsis), - TextUtility.softWrap(true), - TextUtility.textScaleFactor(2.2), - TextUtility.textWidthBasis(TextWidthBasis.longestLine), - TextUtility.maxLines(3), - TextUtility.textAlign(TextAlign.justify), - CommonUtility.textDirection(TextDirection.rtl), - ).text(widgetText), - ), - ); - - final textProp = tester.widget(find.byType(Text)); - - expect(textProp.overflow, TextOverflow.ellipsis); - expect(textProp.softWrap, true); - expect(textProp.textScaleFactor, 2.2); - expect(textProp.textWidthBasis, TextWidthBasis.longestLine); - expect(textProp.maxLines, 3); - expect(textProp.textAlign, TextAlign.justify); - expect(textProp.textDirection, TextDirection.rtl); - }); - - testWidgets('Adds Text Style on widget', (tester) async { - await tester.pumpWidget( - TestMixWidget( - child: StyleMix( - TextUtility.textStyle( - fontSize: 20, - wordSpacing: 2, - letterSpacing: 3, - textBaseline: TextBaseline.ideographic, - fontFamily: 'Roboto', - fontWeight: FontWeight.bold, - color: Colors.amber, - fontStyle: FontStyle.italic, - locale: const Locale('es', 'US'), - height: 10, - backgroundColor: Colors.blue, - ), - ).text(widgetText), - ), - ); - - final textStyle = tester.widget(find.byType(Text)).style!; - - expect(textStyle.fontSize, 20); - expect(textStyle.wordSpacing, 2); - expect(textStyle.letterSpacing, 3); - expect(textStyle.textBaseline, TextBaseline.ideographic); - expect(textStyle.fontFamily, 'Roboto'); - expect(textStyle.fontWeight, FontWeight.bold); - expect(textStyle.color, Colors.amber); - expect(textStyle.fontStyle, FontStyle.italic); - expect(textStyle.locale!.languageCode, 'es'); - expect(textStyle.locale!.countryCode, 'US'); - expect(textStyle.height, 10); - expect(textStyle.backgroundColor, Colors.blue); - }); - - testWidgets('Text Directives', (tester) async { - await tester.pumpWidget( - TestMixWidget( - child: StyleMix( - TextUtility.directives([ - const UppercaseDirective(), - const SentenceCaseDirective(), - const CapitalizeDirective(), - ]), - ).text(widgetText), - ), - ); - - final textWidget = tester.widget(find.byType(Text)); - - expect(textWidget.data, isNot(equals(widgetText))); - - expect(textWidget.data, equals(widgetText.toUpperCase())); - }); - - testWidgets('Resolves text styles', (tester) async { - final ts1 = StyleMix( - textStyle( - fontSize: 20, - wordSpacing: 2, - letterSpacing: 3, - textBaseline: TextBaseline.ideographic, - fontFamily: 'Roboto', - fontWeight: FontWeight.bold, - color: Colors.amber, - fontStyle: FontStyle.italic, - locale: const Locale('es', 'US'), - height: 10, - backgroundColor: Colors.blue, - ), - ); - - final ts2 = StyleMix( - textStyle( - fontSize: 30, - wordSpacing: 3, - letterSpacing: 4, - ), - ); - - final ts3 = StyleMix( - textStyle( - fontSize: 40, - wordSpacing: 4, - letterSpacing: 5, - ), - ); - - final merged = StyleMix.combine([ts1, ts2, ts3]); - - await tester.pumpWidget( - TestMixWidget( - child: merged.text(widgetText), - ), - ); - - final textProp = tester.widget(find.byType(Text)); - - final textAttributes = - merged.values.attributesOfType(); - - expect(textAttributes?.styles?.length, 3); - - expect(textProp.style!.fontSize, 40); - expect(textProp.style!.wordSpacing, 4); - expect(textProp.style!.letterSpacing, 5); - - expect(textProp.style!.textBaseline, TextBaseline.ideographic); - expect(textProp.style!.fontFamily, 'Roboto'); - expect(textProp.style!.fontWeight, FontWeight.bold); - expect(textProp.style!.color, Colors.amber); - expect(textProp.style!.fontStyle, FontStyle.italic); - expect(textProp.style!.locale!.languageCode, 'es'); - expect(textProp.style!.locale!.countryCode, 'US'); - expect(textProp.style!.height, 10); - expect(textProp.style!.backgroundColor, Colors.blue); - - expect(textProp.data, widgetText); - }); - - testWidgets('Resolves TextStyleToken', (tester) async { - final ts1 = StyleMix( - textStyle( - fontSize: 20, - wordSpacing: 2, - letterSpacing: 3, - backgroundColor: Colors.blue, - ), - ); - - const contextStyle = TextStyle( - fontSize: 30, - wordSpacing: 3, - letterSpacing: 4, - ); - - const textStyleToken = TextStyleToken('_test_text_style_token_'); - - final ts2 = StyleMix( - textStyle(as: textStyleToken), - ); - - final ts3 = StyleMix( - textStyle( - letterSpacing: 5, - ), - ); - - final merged = StyleMix.combine([ts1, ts2, ts3]); - - await tester.pumpWidget( - MaterialApp( - theme: ThemeData( - textTheme: const TextTheme( - displaySmall: contextStyle, - ), - ), - home: MixTheme( - data: MixThemeData( - textStyles: { - textStyleToken: (context) => - Theme.of(context).textTheme.displaySmall, - }, - ), - child: TestMixWidget( - child: merged.text(widgetText), - ), - ), - ), - ); - - final textProp = tester.widget(find.byType(Text)); - - expect(textProp.style!.fontSize, 30); - expect(textProp.style!.wordSpacing, 3); - expect(textProp.style!.letterSpacing, 5); - - expect(textProp.style!.backgroundColor, Colors.blue); - }); - }); -} diff --git a/tools/rename_files.dart b/tools/rename_files.dart new file mode 100755 index 000000000..71c00c4f3 --- /dev/null +++ b/tools/rename_files.dart @@ -0,0 +1,34 @@ +import 'dart:io'; + +import 'package:path/path.dart' as p; + +void main() { + final dir = Directory('./lib'); // Starting directory + const searchPattern = '.dto.dart'; + const replacement = '_dto.dart'; + + // 1. Update imports in all Dart files + final allDartFiles = dir.listSync(recursive: true).where((entity) { + return entity is File && entity.path.endsWith('.dart'); + }).cast(); + + for (final file in allDartFiles) { + String content = file.readAsStringSync(); + + content = content.replaceAll(searchPattern, replacement); + + file.writeAsStringSync(content); + } + + // 2. Rename matching files + for (final file in allDartFiles) { + final filename = p.basename(file.path); + if (filename.contains(searchPattern)) { + final newFilename = filename.replaceAll(searchPattern, replacement); + final newPath = p.join(p.dirname(file.path), newFilename); + file.renameSync(newPath); + } + } + + print('Import updates and file renaming completed.'); +} diff --git a/tools/update_exports.dart b/tools/update_exports.dart new file mode 100755 index 000000000..41eaf8e65 --- /dev/null +++ b/tools/update_exports.dart @@ -0,0 +1,40 @@ +#!/usr/bin/env dart + +import 'dart:io'; + +import 'package:path/path.dart' as p; + +void main() { + final libDirectory = Directory('lib'); + final exportFilePath = p.join('lib', 'exports.dart'); + final coreDirectoryPath = + p.join('lib', 'src', 'core'); // Directory to exclude + + if (!libDirectory.existsSync()) { + print('The lib directory was not found.'); + + return; + } + + final exportFile = File(exportFilePath); + if (exportFile.existsSync()) { + exportFile.deleteSync(); + } + + final newExports = {}; + + // Traverse the /lib/ directory + for (final entity in libDirectory.listSync(recursive: true)) { + // Get the relative path using the path package + final relativePath = p.relative(entity.path, from: libDirectory.path); + // Exclude files from the core directory + if (!relativePath.startsWith(p.join('src', 'core')) && + relativePath.endsWith('.dart')) { + newExports.add('export \'$relativePath\';'); + } + } + + exportFile.writeAsStringSync(newExports.join('\n')); + + print('Exports file updated with ${newExports.length} exports.'); +}