diff --git a/.github/workflows/example_app.yml b/.github/workflows/example_app.yml index ac2a8e2..820a5d3 100644 --- a/.github/workflows/example_app.yml +++ b/.github/workflows/example_app.yml @@ -15,7 +15,7 @@ jobs: - uses: actions/setup-java@v3 with: distribution: 'temurin' - java-version: '11' + java-version: '17' - run: dart --version - run: flutter --version - run: flutter analyze diff --git a/CHANGELOG.md b/CHANGELOG.md index 50d2119..7085a4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [3.1.15] - 2025-02-12 + +### Fixed +- Fix button style can not be overridden [#224](https://github.com/Pyozer/introduction_screen/pull/224) + ## [3.1.14] - 2024-03-23 ### Fixed diff --git a/README.md b/README.md index 24c9cdf..3b1f5d2 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ You just need to add `introduction_screen` as a [dependency in your pubspec.yaml ```yaml dependencies: - introduction_screen: ^3.1.14 + introduction_screen: ^3.1.15 ``` ## Examples diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties index e1ca574..8bc9958 100644 --- a/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/example/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-all.zip diff --git a/example/android/settings.gradle b/example/android/settings.gradle index 1d6d19b..0f9d8c9 100644 --- a/example/android/settings.gradle +++ b/example/android/settings.gradle @@ -19,7 +19,7 @@ pluginManagement { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "7.3.0" apply false + id "com.android.application" version "8.1.0" apply false id "org.jetbrains.kotlin.android" version "1.7.10" apply false } diff --git a/lib/src/ui/intro_button.dart b/lib/src/ui/intro_button.dart index 94e6c96..759b82b 100644 --- a/lib/src/ui/intro_button.dart +++ b/lib/src/ui/intro_button.dart @@ -16,6 +16,12 @@ class IntroButton extends StatelessWidget { @override Widget build(BuildContext context) { + final defaultStyle = TextButton.styleFrom( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8.0), + ), + ); + return MergeSemantics( child: Semantics( label: semanticLabel, @@ -23,11 +29,7 @@ class IntroButton extends StatelessWidget { child: TextButton( onPressed: onPressed, child: child, - style: TextButton.styleFrom( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8.0), - ), - ).merge(style), + style: style?.merge(defaultStyle) ?? defaultStyle, ), ), ); diff --git a/pubspec.yaml b/pubspec.yaml index 5857771..2967275 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: introduction_screen description: Introduction/Onboarding package for flutter app with some customizations possibilities -version: 3.1.14 +version: 3.1.15 repository: https://github.com/pyozer/introduction_screen issue_tracker: https://github.com/pyozer/introduction_screen/issues diff --git a/test/src/helper_test.dart b/test/src/helper_test.dart index 64cef0b..67e2dc5 100644 --- a/test/src/helper_test.dart +++ b/test/src/helper_test.dart @@ -4,31 +4,26 @@ import 'package:introduction_screen/src/helper.dart'; void main() { // Global variables final originalList = [1, 2, 3, 4, 5]; - final list = ['a', 'b', 'c']; group('CustomList', () { - test('asReversed returns reversed list when isReverse is true', () { - final reversedList = originalList.asReversed(true); - - expect(reversedList, [5, 4, 3, 2, 1]); + test('asReversed() reverses list when isReverse is true', () { + expect(originalList.asReversed(true), [5, 4, 3, 2, 1]); }); - test('asReversed returns original list when isReverse is false', () { - final originalCopy = originalList.asReversed(false); - - expect(originalCopy, originalList); + test('asReversed() returns original list when isReverse is false', () { + expect(originalList.asReversed(false), [1, 2, 3, 4, 5]); }); test('elementAtOrNull returns the correct element for valid index', () { - expect(list.elementAtOrNull(1), 'b'); + expect(originalList.elementAtOrNull(1), 2); }); test('elementAtOrNull returns null for out of bounds index', () { - expect(list.elementAtOrNull(5), isNull); + expect(originalList.elementAtOrNull(5), isNull); }); test('elementAtOrNull returns null for negative index', () { - expect(list.elementAtOrNull(-1), isNull); + expect(originalList.elementAtOrNull(-1), isNull); }); }); } diff --git a/test/src/introduction_screen_test.dart b/test/src/introduction_screen_test.dart index a746e7d..e614f9e 100644 --- a/test/src/introduction_screen_test.dart +++ b/test/src/introduction_screen_test.dart @@ -1,6 +1,6 @@ import 'package:dots_indicator/dots_indicator.dart'; -import 'package:flutter_test/flutter_test.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; import 'package:introduction_screen/introduction_screen.dart'; void main() { @@ -12,6 +12,8 @@ void main() { bool showSkipButton = false, bool showDoneButton = false, bool showNextButton = true, + bool showBackButton = false, + int initialPage = 0, int? autoScrollDuration, }) { return MaterialApp( @@ -24,8 +26,11 @@ void main() { next: showNextButton ? Text("Next") : null, showSkipButton: showSkipButton, showDoneButton: showDoneButton, + showBackButton: showBackButton, + back: showBackButton ? Text("Back") : null, showNextButton: showNextButton, autoScrollDuration: autoScrollDuration, + initialPage: initialPage, ), ); } @@ -64,6 +69,29 @@ void main() { expect(find.text('Page 2'), findsOneWidget); }); + testWidgets('Back button goes back to the previous page', (tester) async { + // Arrange + await tester.pumpWidget(createIntroductionScreen( + pages: [ + PageViewModel(title: 'Page 1', body: 'Introduction 1'), + PageViewModel(title: 'Page 2', body: 'Introduction 2'), + ], + showBackButton: true, + initialPage: 1, + )); + + expect(find.text('Page 1'), findsNothing); + expect(find.text('Page 2'), findsOneWidget); + + // Act + await tester.tap(find.text('Back')); + await tester.pumpAndSettle(); + + // Assert + expect(find.text('Page 1'), findsOneWidget); + expect(find.text('Page 2'), findsNothing); + }); + testWidgets('Skip button triggers onSkip callback', (tester) async { // Arrange var skipTapped = false; @@ -167,24 +195,40 @@ void main() { }); }); - testWidgets('Auto-scroll works as expected', (WidgetTester tester) async { + testWidgets('Auto-scroll advances one page at a time', + (WidgetTester tester) async { // Arrange - final pages = [ - PageViewModel(title: 'Page 1', body: 'Introduction 1'), - PageViewModel(title: 'Page 2', body: 'Introduction 2'), - ]; - - await tester.pumpWidget( - createIntroductionScreen(pages: pages, autoScrollDuration: 5)); + const autoScrollDuration = 2000; + await tester.pumpWidget(createIntroductionScreen( + pages: [ + PageViewModel(title: 'Page 1', body: 'Introduction 1'), + PageViewModel(title: 'Page 2', body: 'Introduction 2'), + PageViewModel(title: 'Page 3', body: 'Introduction 3'), + ], + autoScrollDuration: autoScrollDuration, + )); - // Initial page should be Page 1 + // Should still be at page 1 after 100 ms + await tester.pump(Duration(milliseconds: 100)); + await tester.pumpAndSettle(); expect(find.text('Page 1'), findsOneWidget); + expect(find.text('Page 2'), findsNothing); + expect(find.text('Page 3'), findsNothing); - // Simulate time passing to trigger auto-scroll - await tester.pump(const Duration(milliseconds: 10)); + // Wait for first auto-scroll, should be on page 2 now + await tester.pump(Duration(milliseconds: autoScrollDuration + 100)); await tester.pumpAndSettle(); - // The auto-scroll should have moved to the next page + expect(find.text('Page 1'), findsNothing); expect(find.text('Page 2'), findsOneWidget); + expect(find.text('Page 3'), findsNothing); + + // Wait for second auto-scroll, should be on page 3 now + await tester.pump(Duration(milliseconds: autoScrollDuration)); + await tester.pumpAndSettle(); + + expect(find.text('Page 1'), findsNothing); + expect(find.text('Page 2'), findsNothing); + expect(find.text('Page 3'), findsOneWidget); }); } diff --git a/test/widget/intro_ui_test.dart b/test/widget/intro_ui_test.dart index 35023a9..efef456 100644 --- a/test/widget/intro_ui_test.dart +++ b/test/widget/intro_ui_test.dart @@ -125,5 +125,37 @@ void main() { // Check that the image is rendered expect(find.byWidget(mockImage), findsOneWidget); }); + + testWidgets('IntroButton custom styles override default styles', + (tester) async { + // Create a custom style with a different border radius + final customStyle = TextButton.styleFrom( + shape: RoundedRectangleBorder( + borderRadius: + BorderRadius.circular(20.0), // Different from default 8.0 + ), + backgroundColor: Colors.blue, // Additional property to verify + ); + + await tester.pumpWidget(testableWidget( + child: IntroButton( + child: const Text('Test Text'), + style: customStyle, + ), + )); + + // Find the TextButton + final button = tester.widget(find.byType(TextButton)); + + // Get the shape from the button's style + final shape = button.style?.shape?.resolve({}); + expect(shape, isA()); + final borderRadius = (shape as RoundedRectangleBorder).borderRadius; + expect(borderRadius, BorderRadius.circular(20.0)); + + // Verify the background color was also applied + final backgroundColor = button.style?.backgroundColor?.resolve({}); + expect(backgroundColor, Colors.blue); + }); }); }