diff --git a/.github/workflows/on-main.yml b/.github/workflows/on-main.yml
index bb3b9aa4..15fb2e0e 100644
--- a/.github/workflows/on-main.yml
+++ b/.github/workflows/on-main.yml
@@ -33,6 +33,7 @@ jobs:
dart format . -l 120
dart fix --apply
flutter analyze
+ flutter test
cd example && flutter test
- name: Check for modified files
id: git-check
diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml
index dab856c5..72c1158a 100644
--- a/.github/workflows/pull-request.yml
+++ b/.github/workflows/pull-request.yml
@@ -66,6 +66,7 @@ jobs:
dart format . -l 120
dart fix --apply
flutter analyze
+ flutter test
cd example && flutter test
- name: Check for modified files
id: git-check
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 4b53985d..24c127c2 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -34,6 +34,127 @@ For more information on widgetbook, [read the docs](https://docs.widgetbook.io/)
We should also create a test for each widget created.
+### Contributing Guide for Writing Tests
+
+#### Folder Structure
+
+To maintain consistency and ease of navigation, follow the same folder structure in the `test` directory as in the `lib` directory. For example, if you have a file located at `lib/src/components/tooltip/tooltip.dart`, your test file should be located at `test/src/components/tooltip/tooltip_test.dart`.
+
+##### Example Folder Structure
+
+```
+lib/
+└── src/
+ └── components/
+ └── tooltip/
+ └── tooltip.dart
+
+test/
+└── src/
+ └── components/
+ └── tooltip/
+ └── tooltip_test.dart
+```
+
+#### Writing Tests
+
+1. **Unit Tests**: Test individual functions and classes.
+2. **Widget Tests**: Test individual widgets and their interactions.
+3. **Integration Tests**: Test the complete app or large parts of it.
+
+##### Guidelines
+
+- Use descriptive test names.
+- Test one thing per test.
+- Mock dependencies using `mockito`.
+- Write tests for edge cases.
+
+#### Measuring Code Coverage
+
+To ensure high code coverage (at least > 96%), use the following steps:
+
+##### With 'lcov'
+1. **Run the script coverage.sh from the project root, which make use of `lcov` to generate the coverage report**:
+ ```sh
+ sh coverage.sh
+ ```
+##### Alternatively, with 'genhtml'
+1. **Install dependencies**:
+ ```sh
+ flutter pub add --dev test coverage
+ ```
+
+2. **Run tests with coverage**:
+ ```sh
+ flutter test --coverage
+ ```
+
+3. **Generate coverage report**:
+ ```sh
+ genhtml coverage/lcov.info -o coverage/html
+ ```
+
+4. **View coverage report**:
+ Open `coverage/html/index.html` in a web browser.
+
+
+##### Maximizing Coverage
+
+- Write tests for all public methods and classes.
+- Include tests for edge cases and error handling.
+- Avoid excluding files from coverage unless necessary.
+
+#### Golden Tests
+
+Golden tests are used to ensure that the visual output of your widgets remains consistent over time. They are particularly useful for complex UI components.
+
+##### Why Golden Tests?
+
+In the `tooltip` example, the direction of the arrows in the tooltip is crucial. Golden tests help to ensure that any changes to the tooltip do not unintentionally alter the direction of the arrows or other visual aspects.
+
+##### Adding Golden Tests
+
+1. **Set up golden tests**:
+ ```dart
+ import 'package:flutter_test/flutter_test.dart';
+ import 'package:zeta_flutter/zeta_flutter.dart';
+
+ import '../../../test_utils/test_app.dart';
+
+ void main() {
+ testWidgets('renders with arrow correctly in up direction', (WidgetTester tester) async {
+ await tester.pumpWidget(
+ const TestApp(
+ home: Scaffold(
+ body: ZetaTooltip(
+ arrowDirection: ZetaTooltipArrowDirection.up,
+ child: Text('Tooltip up'),
+ ),
+ ),
+ ),
+ );
+
+ expect(find.text('Tooltip up'), findsOneWidget);
+
+ // Verifying the CustomPaint with different arrow directions.
+ await expectLater(
+ find.byType(ZetaTooltip),
+ matchesGoldenFile(p.join('golden', 'arrow_up.png')),
+ );
+ });
+ }
+ ```
+
+2. **Run golden tests**:
+ ```sh
+ flutter test --update-goldens
+ ```
+
+3. **Verify golden tests**:
+ Ensure that the generated golden files are correct and commit them to the repository.
+
+
+
## Code reviews
All submissions, including submissions by project members, require review. We use GitHub pull requests (PRs) for this purpose. Consult [GitHub Help](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests) for more information on using pull requests.
diff --git a/coverage.sh b/coverage.sh
new file mode 100644
index 00000000..a20e51f0
--- /dev/null
+++ b/coverage.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+# Check if lcov is installed
+if ! command -v lcov &> /dev/null
+then
+ echo "lcov could not be found, please install it first."
+ exit
+fi
+
+# Run the tests with coverage
+flutter test --coverage
+
+# Generate the LCOV report
+lcov --capture --directory coverage --output-file coverage/lcov.info
+
+# Remove unnecessary files from the report
+lcov --remove coverage/lcov.info 'lib/*/*.g.dart' 'lib/*/*.freezed.dart' -o coverage/lcov.info
+
+# Generate the HTML report
+genhtml coverage/lcov.info --output-directory coverage/html
+
+# Open the coverage report in the default browser
+if [ "$(uname)" == "Darwin" ]; then
+ open coverage/html/index.html
+elif [ "$(uname)" == "Linux" ]; then
+ xdg-open coverage/html/index.html
+elif [ "$(uname)" == "CYGWIN" ] || [ "$(uname)" == "MINGW32" ] || [ "$(uname)" == "MINGW64" ]; then
+ start coverage/html/index.html
+fi
+
+echo "Coverage report generated and opened in the default browser."
diff --git a/example/ios/Flutter/AppFrameworkInfo.plist b/example/ios/Flutter/AppFrameworkInfo.plist
index 9625e105..7c569640 100644
--- a/example/ios/Flutter/AppFrameworkInfo.plist
+++ b/example/ios/Flutter/AppFrameworkInfo.plist
@@ -21,6 +21,6 @@
CFBundleVersion
1.0
MinimumOSVersion
- 11.0
+ 12.0
diff --git a/example/ios/Podfile b/example/ios/Podfile
index 88359b22..279576f3 100644
--- a/example/ios/Podfile
+++ b/example/ios/Podfile
@@ -1,5 +1,5 @@
# Uncomment this line to define a global platform for your project
-# platform :ios, '11.0'
+# platform :ios, '12.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock
index f6342e74..15073017 100644
--- a/example/ios/Podfile.lock
+++ b/example/ios/Podfile.lock
@@ -6,11 +6,18 @@ PODS:
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
+ - sqflite (0.0.3):
+ - Flutter
+ - FlutterMacOS
+ - url_launcher_ios (0.0.1):
+ - Flutter
DEPENDENCIES:
- Flutter (from `Flutter`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
+ - sqflite (from `.symlinks/plugins/sqflite/darwin`)
+ - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
EXTERNAL SOURCES:
Flutter:
@@ -19,12 +26,18 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/path_provider_foundation/darwin"
shared_preferences_foundation:
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
+ sqflite:
+ :path: ".symlinks/plugins/sqflite/darwin"
+ url_launcher_ios:
+ :path: ".symlinks/plugins/url_launcher_ios/ios"
SPEC CHECKSUMS:
- Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
- path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
- shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126
+ Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
+ path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
+ shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
+ sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
+ url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
-PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3
+PODFILE CHECKSUM: c4c93c5f6502fe2754f48404d3594bf779584011
-COCOAPODS: 1.14.3
+COCOAPODS: 1.15.2
diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj
index 83853dd6..62e10fdd 100644
--- a/example/ios/Runner.xcodeproj/project.pbxproj
+++ b/example/ios/Runner.xcodeproj/project.pbxproj
@@ -156,7 +156,7 @@
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 1430;
+ LastUpgradeCheck = 1510;
ORGANIZATIONNAME = "";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
@@ -343,7 +343,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 11.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
@@ -421,7 +421,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 11.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@@ -470,7 +470,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 11.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
index a6b826db..5e31d3d3 100644
--- a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
+++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -1,6 +1,6 @@
(
value: e.value.identifier,
alignment: Alignment.center,
- child: CircleAvatar(
+ child: ZetaAvatar(
+ size: ZetaAvatarSize.xxs,
backgroundColor: color.surface,
- foregroundColor: color,
- child: Icon(Icons.color_lens, color: color),
+ image: Icon(Icons.color_lens, color: color),
),
);
}).toList(),
diff --git a/example/lib/utils/theme_constrast_switch.dart b/example/lib/utils/theme_constrast_switch.dart
index 780acd01..7e7c060d 100644
--- a/example/lib/utils/theme_constrast_switch.dart
+++ b/example/lib/utils/theme_constrast_switch.dart
@@ -34,12 +34,14 @@ class ZetaThemeContrastSwitch extends StatelessWidget {
return DropdownMenuItem(
value: e,
alignment: Alignment.center,
- child: CircleAvatar(
+ child: ZetaAvatar(
+ size: ZetaAvatarSize.xxs,
backgroundColor: colors.primary.surface,
- foregroundColor: colors.primary,
- child: Text(
- e == ZetaContrast.aa ? 'AA' : 'AAA',
- style: ZetaTextStyles.bodyMedium.copyWith(color: colors.primary, fontWeight: FontWeight.w700),
+ image: Center(
+ child: Text(
+ e == ZetaContrast.aa ? 'AA' : 'AAA',
+ style: ZetaTextStyles.bodyMedium.copyWith(color: colors.primary, fontWeight: FontWeight.w700),
+ ),
),
),
);
diff --git a/example/lib/utils/theme_mode_switch.dart b/example/lib/utils/theme_mode_switch.dart
index fb9a22e1..200ceeba 100644
--- a/example/lib/utils/theme_mode_switch.dart
+++ b/example/lib/utils/theme_mode_switch.dart
@@ -36,10 +36,10 @@ class ZetaThemeModeSwitch extends StatelessWidget {
return DropdownMenuItem(
value: e,
alignment: Alignment.center,
- child: CircleAvatar(
+ child: ZetaAvatar(
+ size: ZetaAvatarSize.xxs,
backgroundColor: colors.primary.surface,
- foregroundColor: colors.primary,
- child: Icon(
+ image: Icon(
e == ThemeMode.system
? Icons.system_security_update_good
: e == ThemeMode.light
diff --git a/golden/arrow_down.png b/golden/arrow_down.png
new file mode 100644
index 00000000..aa995748
Binary files /dev/null and b/golden/arrow_down.png differ
diff --git a/golden/arrow_left.png b/golden/arrow_left.png
new file mode 100644
index 00000000..7f66b33e
Binary files /dev/null and b/golden/arrow_left.png differ
diff --git a/golden/arrow_right.png b/golden/arrow_right.png
new file mode 100644
index 00000000..30d99000
Binary files /dev/null and b/golden/arrow_right.png differ
diff --git a/golden/arrow_up.png b/golden/arrow_up.png
new file mode 100644
index 00000000..da590cb5
Binary files /dev/null and b/golden/arrow_up.png differ
diff --git a/lib/src/theme/color_swatch.dart b/lib/src/theme/color_swatch.dart
index 470eb16d..20c3ddb1 100644
--- a/lib/src/theme/color_swatch.dart
+++ b/lib/src/theme/color_swatch.dart
@@ -1,3 +1,4 @@
+import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'color_extensions.dart';
@@ -6,7 +7,7 @@ import 'contrast.dart';
/// A swatch of colors with values from 10 (light) to 100 (dark).
@immutable
-class ZetaColorSwatch extends ColorSwatch {
+class ZetaColorSwatch extends ColorSwatch with EquatableMixin {
/// Constructs a [ZetaColorSwatch].
///
/// See also:
@@ -142,7 +143,8 @@ class ZetaColorSwatch extends ColorSwatch {
/// Returns the color shade for a subtle visual element depending on the ZetaContrast value.
///
- /// For both [ZetaContrast.aa] and [ZetaContrast.aaa], it returns 40.
+ /// For [ZetaContrast.aa], it returns 40.
+ /// For [ZetaContrast.aaa], it returns 60.
Color get subtle => shade(contrast.subtle);
/// Returns the color shade for a surface depending on the ZetaContrast value.
@@ -185,14 +187,19 @@ class ZetaColorSwatch extends ColorSwatch {
}
@override
- bool operator ==(Object other) =>
- identical(this, other) ||
- super == other &&
- other is ZetaColorSwatch &&
- runtimeType == other.runtimeType &&
- brightness == other.brightness &&
- contrast == other.contrast;
-
- @override
- int get hashCode => super.hashCode ^ brightness.hashCode ^ contrast.hashCode;
+ List