diff --git a/CHANGELOG.md b/CHANGELOG.md index 1edcec8..eac25cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 3.1.0 + +* Introduction now uses `IntroductionScreenMode` to determine how often the introductions should be shown +* Added `dotSize` and `dotSpacing` to `IntroductionOptions` to allow for customization of the dots for the introduction + ## 3.0.0 * Update default styling diff --git a/packages/flutter_introduction/lib/flutter_introduction.dart b/packages/flutter_introduction/lib/flutter_introduction.dart index a45d215..d90c229 100644 --- a/packages/flutter_introduction/lib/flutter_introduction.dart +++ b/packages/flutter_introduction/lib/flutter_introduction.dart @@ -56,7 +56,9 @@ class _IntroductionState extends State { // ignore: discarded_futures future: _service.shouldShow(), builder: (context, snapshot) { - if (snapshot.data == null || snapshot.data!) { + if (snapshot.data == null || + snapshot.data! || + widget.options.mode == IntroductionScreenMode.showAlways) { return IntroductionScreen( options: widget.options, onComplete: () async { diff --git a/packages/flutter_introduction/pubspec.yaml b/packages/flutter_introduction/pubspec.yaml index b2a5053..01afa4e 100644 --- a/packages/flutter_introduction/pubspec.yaml +++ b/packages/flutter_introduction/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_introduction description: Combined Package of Flutter Introduction Widget and Flutter Introduction Service -version: 3.0.0 +version: 3.1.0 publish_to: none environment: @@ -13,12 +13,12 @@ dependencies: flutter_introduction_widget: git: url: https://github.com/Iconica-Development/flutter_introduction - ref: 3.0.0 + ref: 3.1.0 path: packages/flutter_introduction_widget flutter_introduction_service: git: url: https://github.com/Iconica-Development/flutter_introduction - ref: 3.0.0 + ref: 3.1.0 path: packages/flutter_introduction_service dev_dependencies: diff --git a/packages/flutter_introduction_firebase/pubspec.yaml b/packages/flutter_introduction_firebase/pubspec.yaml index e55dd08..4280a8e 100644 --- a/packages/flutter_introduction_firebase/pubspec.yaml +++ b/packages/flutter_introduction_firebase/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_introduction_firebase description: Flutter Introduction Page that uses firebase for the pages and some settings -version: 3.0.0 +version: 3.1.0 publish_to: none environment: @@ -15,12 +15,12 @@ dependencies: flutter_introduction_widget: git: url: https://github.com/Iconica-Development/flutter_introduction - ref: 3.0.0 + ref: 3.1.0 path: packages/flutter_introduction_widget flutter_introduction_service: git: url: https://github.com/Iconica-Development/flutter_introduction - ref: 3.0.0 + ref: 3.1.0 path: packages/flutter_introduction_service dev_dependencies: diff --git a/packages/flutter_introduction_interface/pubspec.yaml b/packages/flutter_introduction_interface/pubspec.yaml index b331169..9201487 100644 --- a/packages/flutter_introduction_interface/pubspec.yaml +++ b/packages/flutter_introduction_interface/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_introduction_interface description: A new Flutter package project. -version: 3.0.0 +version: 3.1.0 publish_to: none environment: diff --git a/packages/flutter_introduction_service/pubspec.yaml b/packages/flutter_introduction_service/pubspec.yaml index cfb2e99..9979b50 100644 --- a/packages/flutter_introduction_service/pubspec.yaml +++ b/packages/flutter_introduction_service/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_introduction_service description: A new Flutter package project. -version: 3.0.0 +version: 3.1.0 publish_to: none environment: @@ -13,7 +13,7 @@ dependencies: flutter_introduction_interface: git: url: https://github.com/Iconica-Development/flutter_introduction - ref: 3.0.0 + ref: 3.1.0 path: packages/flutter_introduction_interface dev_dependencies: diff --git a/packages/flutter_introduction_shared_preferences/pubspec.yaml b/packages/flutter_introduction_shared_preferences/pubspec.yaml index 229c931..a2716b3 100644 --- a/packages/flutter_introduction_shared_preferences/pubspec.yaml +++ b/packages/flutter_introduction_shared_preferences/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_introduction_shared_preferences description: A new Flutter package project. -version: 3.0.0 +version: 3.1.0 publish_to: none environment: @@ -13,7 +13,7 @@ dependencies: flutter_introduction_interface: git: url: https://github.com/Iconica-Development/flutter_introduction - ref: 3.0.0 + ref: 3.1.0 path: packages/flutter_introduction_interface shared_preferences: any diff --git a/packages/flutter_introduction_widget/assets/first.png b/packages/flutter_introduction_widget/assets/first.png index e2283e4..c7f7aa4 100644 Binary files a/packages/flutter_introduction_widget/assets/first.png and b/packages/flutter_introduction_widget/assets/first.png differ diff --git a/packages/flutter_introduction_widget/assets/second.png b/packages/flutter_introduction_widget/assets/second.png index a3dc5f4..d744576 100644 Binary files a/packages/flutter_introduction_widget/assets/second.png and b/packages/flutter_introduction_widget/assets/second.png differ diff --git a/packages/flutter_introduction_widget/assets/third.png b/packages/flutter_introduction_widget/assets/third.png index f67e47c..0b77c55 100644 Binary files a/packages/flutter_introduction_widget/assets/third.png and b/packages/flutter_introduction_widget/assets/third.png differ diff --git a/packages/flutter_introduction_widget/lib/src/config/default_introduction_pages.dart b/packages/flutter_introduction_widget/lib/src/config/default_introduction_pages.dart index e5c38aa..4331983 100644 --- a/packages/flutter_introduction_widget/lib/src/config/default_introduction_pages.dart +++ b/packages/flutter_introduction_widget/lib/src/config/default_introduction_pages.dart @@ -1,33 +1,16 @@ + import 'package:flutter/material.dart'; import 'package:flutter_introduction_widget/flutter_introduction_widget.dart'; const List defaultIntroductionPages = [ IntroductionPage( - decoration: BoxDecoration( - color: Color(0xffFAF9F6), - ), title: Column( children: [ - SizedBox(height: 100), + SizedBox(height: 50), Text( 'welcome to iconinstagram', - style: TextStyle( - color: Color(0xff71C6D1), - fontSize: 24, - fontWeight: FontWeight.w700, - ), ), SizedBox(height: 6), - Text( - 'Welcome to the world of Instagram, where creativity' - ' knows no bounds and connections are made' - ' through captivating visuals.', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w400, - ), - textAlign: TextAlign.center, - ), ], ), graphic: Image( @@ -36,72 +19,46 @@ const List defaultIntroductionPages = [ package: 'flutter_introduction_widget', ), ), - text: Text(''), + text: Text( + 'Welcome to the world of Instagram, where creativity' + ' knows no bounds and connections are made' + ' through captivating visuals.', + textAlign: TextAlign.center, + ), ), IntroductionPage( - decoration: BoxDecoration( - color: Color(0xffFAF9F6), - ), title: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - SizedBox(height: 100), + SizedBox(height: 50), Text( 'discover iconinstagram', - style: TextStyle( - color: Color(0xff71C6D1), - fontSize: 24, - fontWeight: FontWeight.w700, - ), ), SizedBox(height: 6), - Text( - 'Dive into the vibrant world of' - ' Instagram and discover endless possibilities.' - ' From stunning photography to engaging videos,' - ' Instagram offers a diverse range of content to explore and enjoy.', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w400, - ), - textAlign: TextAlign.center, - ), ], ), + text: Text( + 'Dive into the vibrant world of' + ' Instagram and discover endless possibilities.' + ' From stunning photography to engaging videos,' + ' Instagram offers a diverse range of content to explore and enjoy.', + textAlign: TextAlign.center, + ), graphic: Image( image: AssetImage( 'assets/second.png', package: 'flutter_introduction_widget', ), ), - text: Text(''), ), IntroductionPage( - decoration: BoxDecoration( - color: Color(0xffFAF9F6), - ), title: Column( children: [ - SizedBox(height: 100), + SizedBox(height: 50), Text( 'elevate your experience', - style: TextStyle( - color: Color(0xff71C6D1), - fontSize: 24, - fontWeight: FontWeight.w700, - ), ), SizedBox(height: 6), - Text( - 'Whether promoting your business, or connecting' - ' with friends and family, Instagram provides the' - ' tools and platform to make your voice heard.', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w400, - ), - textAlign: TextAlign.center, - ), ], ), graphic: Image( @@ -110,6 +67,11 @@ const List defaultIntroductionPages = [ package: 'flutter_introduction_widget', ), ), - text: Text(''), + text: Text( + 'Whether promoting your business, or connecting' + ' with friends and family, Instagram provides the' + ' tools and platform to make your voice heard.', + textAlign: TextAlign.center, + ), ), ]; diff --git a/packages/flutter_introduction_widget/lib/src/config/introduction.dart b/packages/flutter_introduction_widget/lib/src/config/introduction.dart index 37f19f4..47d6127 100644 --- a/packages/flutter_introduction_widget/lib/src/config/introduction.dart +++ b/packages/flutter_introduction_widget/lib/src/config/introduction.dart @@ -63,7 +63,7 @@ class IntroductionOptions { this.introductionButtonTextstyles = const IntroductionButtonTextstyles(), this.indicatorMode = IndicatorMode.dot, this.indicatorBuilder, - this.layoutStyle = IntroductionLayoutStyle.imageCenter, + this.layoutStyle = IntroductionLayoutStyle.imageBottom, this.pages = defaultIntroductionPages, this.buttonMode = IntroductionScreenButtonMode.text, this.tapEnabled = false, @@ -73,6 +73,8 @@ class IntroductionOptions { this.skippable = false, this.buttonBuilder, this.controlMode = IntroductionControlMode.previousNextButton, + this.dotSize = 12, + this.dotSpacing = 24, }) : assert( !(identical(indicatorMode, IndicatorMode.custom) && indicatorBuilder == null), @@ -204,6 +206,12 @@ class IntroductionOptions { /// - Finish final IntroductionButtonTextstyles introductionButtonTextstyles; + /// The size of the dots in the indicator. Default is 12 + final double dotSize; + + /// The distance between the center of each dot. Default is 24 + final double dotSpacing; + IntroductionOptions copyWith({ IntroductionScreenMode? mode, List? pages, @@ -248,7 +256,7 @@ class IntroductionOptions { class IntroductionTranslations { const IntroductionTranslations({ - this.skipButton = 'skip', + this.skipButton = 'Skip', this.nextButton = 'Next', this.previousButton = 'Previous', this.finishButton = 'Get Started', diff --git a/packages/flutter_introduction_widget/lib/src/types/page_introduction.dart b/packages/flutter_introduction_widget/lib/src/types/page_introduction.dart index 18cf936..8ea8a46 100644 --- a/packages/flutter_introduction_widget/lib/src/types/page_introduction.dart +++ b/packages/flutter_introduction_widget/lib/src/types/page_introduction.dart @@ -155,10 +155,15 @@ class _MultiPageIntroductionScreenState controller: _controller, count: pages.length, index: _currentPage.value, + dotSize: widget.options.dotSize, + dotSpacing: widget.options.dotSpacing, ), ), Padding( - padding: const EdgeInsets.all(32), + padding: const EdgeInsets.symmetric( + vertical: 40, + horizontal: 20, + ), child: AnimatedBuilder( animation: _controller, builder: (context, _) { @@ -270,14 +275,14 @@ class ExplainerPage extends StatelessWidget { title: Padding( padding: const EdgeInsets.symmetric(horizontal: 32), child: DefaultTextStyle( - style: theme.textTheme.displayMedium!, + style: theme.textTheme.titleMedium!, child: page.title ?? Text('introduction.$index.title'), ), ), text: Padding( padding: const EdgeInsets.symmetric(horizontal: 32), child: DefaultTextStyle( - style: theme.textTheme.bodyLarge!, + style: theme.textTheme.bodyMedium!, child: page.text ?? Text('introduction.$index.description'), ), ), @@ -340,116 +345,148 @@ class IntroductionTwoButtons extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ if (options.buttonMode == IntroductionScreenButtonMode.text) ...[ - if (previous) ...[ - options.buttonBuilder?.call( - context, - _previous, - Text( - translations.previousButton, - style: options - .introductionButtonTextstyles.previousButtonStyle, - ), - IntroductionButtonType.previous, - ) ?? - InkWell( - onTap: _previous, - child: Container( - width: 180, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - border: Border.all( - color: const Color( - 0xff979797, + Flexible( + child: Padding( + padding: const EdgeInsets.only(right: 6), + child: ConstrainedBox( + constraints: const BoxConstraints( + maxWidth: 180, + ), + child: Opacity( + opacity: previous ? 1 : 0, + child: IgnorePointer( + ignoring: !previous, + child: options.buttonBuilder?.call( + context, + _previous, + Text( + translations.previousButton, + style: options.introductionButtonTextstyles + .previousButtonStyle, + ), + IntroductionButtonType.previous, + ) ?? + InkWell( + onTap: _previous, + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + border: Border.all( + color: const Color( + 0xff979797, + ), + ), + ), + child: Center( + child: Padding( + padding: + const EdgeInsets.symmetric(vertical: 4), + child: Text( + translations.previousButton, + style: options.introductionButtonTextstyles + .previousButtonStyle, + ), + ), + ), + ), ), - ), - ), - child: Center( - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 2.0), - child: Text( - translations.previousButton, - style: options - .introductionButtonTextstyles.previousButtonStyle, - ), - ), - ), ), ), - ] else - const SizedBox.shrink(), + ), + ), + ), if (next) ...[ - options.buttonBuilder?.call( - context, - _next, - Text( - translations.nextButton, - style: options.introductionButtonTextstyles.nextButtonStyle, + Flexible( + child: Padding( + padding: const EdgeInsets.only(left: 6), + child: ConstrainedBox( + constraints: const BoxConstraints( + maxWidth: 180, ), - IntroductionButtonType.next, - ) ?? - InkWell( - onTap: _next, - child: Container( - width: 180, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - border: Border.all( - color: const Color( - 0xff979797, - ), - ), - ), - child: Center( - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 2.0), - child: Text( + child: options.buttonBuilder?.call( + context, + _next, + Text( translations.nextButton, style: options .introductionButtonTextstyles.nextButtonStyle, ), - ), - ), - ), - ), - ] else if (last) ...[ - options.buttonBuilder?.call( - context, - () { - onFinish?.call(); - }, - Text( - translations.finishButton, - style: - options.introductionButtonTextstyles.finishButtonStyle, - ), - IntroductionButtonType.finish, - ) ?? - InkWell( - onTap: () { - onFinish?.call(); - }, - child: Container( - width: 180, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - border: Border.all( - color: const Color( - 0xff979797, + IntroductionButtonType.next, + ) ?? + InkWell( + onTap: _next, + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + border: Border.all( + color: const Color( + 0xff979797, + ), + ), + ), + child: Center( + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 4), + child: Text( + translations.nextButton, + style: options.introductionButtonTextstyles + .nextButtonStyle, + ), + ), + ), ), ), - ), - child: Center( - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 2.0), - child: Text( + ), + ), + ), + ] else if (last) ...[ + Flexible( + child: Padding( + padding: const EdgeInsets.only(left: 6), + child: ConstrainedBox( + constraints: const BoxConstraints( + maxWidth: 180, + ), + child: options.buttonBuilder?.call( + context, + () { + onFinish?.call(); + }, + Text( translations.finishButton, style: options .introductionButtonTextstyles.finishButtonStyle, ), + IntroductionButtonType.finish, + ) ?? + InkWell( + onTap: () { + onFinish?.call(); + }, + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + border: Border.all( + color: const Color( + 0xff979797, + ), + ), + ), + child: Center( + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 4), + child: Text( + translations.finishButton, + style: options.introductionButtonTextstyles + .finishButtonStyle, + ), + ), + ), + ), ), - ), - ), ), + ), + ), ] else ...[ const SizedBox.shrink(), ], @@ -463,44 +500,51 @@ class IntroductionTwoButtons extends StatelessWidget { maintainState: true, maintainInteractivity: false, child: Align( - child: options.buttonBuilder?.call( - context, - () { - onFinish?.call(); - }, - Text( - translations.finishButton, - style: options - .introductionButtonTextstyles.finishButtonStyle, - ), - IntroductionButtonType.finish, - ) ?? - InkWell( - onTap: () { - onFinish?.call(); - }, - child: Container( - width: 180, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - border: Border.all( - color: const Color( - 0xff979797, - ), - ), - ), - child: Center( - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 2.0), - child: Text( - translations.finishButton, - style: options.introductionButtonTextstyles - .finishButtonStyle, - ), - ), - ), - ), + child: Flexible( + child: ConstrainedBox( + constraints: const BoxConstraints( + maxWidth: 180, ), + child: options.buttonBuilder?.call( + context, + () { + onFinish?.call(); + }, + Text( + translations.finishButton, + style: options + .introductionButtonTextstyles.finishButtonStyle, + ), + IntroductionButtonType.finish, + ) ?? + InkWell( + onTap: () { + onFinish?.call(); + }, + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + border: Border.all( + color: const Color( + 0xff979797, + ), + ), + ), + child: Center( + child: Padding( + padding: + const EdgeInsets.symmetric(vertical: 4), + child: Text( + translations.finishButton, + style: options.introductionButtonTextstyles + .finishButtonStyle, + ), + ), + ), + ), + ), + ), + ), ), ), ), diff --git a/packages/flutter_introduction_widget/lib/src/widgets/indicator.dart b/packages/flutter_introduction_widget/lib/src/widgets/indicator.dart index e967315..3fc4729 100644 --- a/packages/flutter_introduction_widget/lib/src/widgets/indicator.dart +++ b/packages/flutter_introduction_widget/lib/src/widgets/indicator.dart @@ -3,7 +3,6 @@ // SPDX-License-Identifier: BSD-3-Clause import 'dart:async'; -import 'dart:math'; import 'package:flutter/material.dart'; import 'package:flutter_introduction_widget/src/config/introduction.dart'; @@ -16,6 +15,8 @@ class Indicator extends StatelessWidget { required this.count, required this.index, required this.indicatorBuilder, + required this.dotSize, + required this.dotSpacing, super.key, }) : assert( !(mode == IndicatorMode.custom && indicatorBuilder == null), @@ -39,6 +40,12 @@ class Indicator extends StatelessWidget { final Widget Function(BuildContext, PageController, int, int)? indicatorBuilder; + /// The size of the dots. + final double dotSize; + + /// The distance between the center of each dot. + final double dotSpacing; + @override Widget build(BuildContext context) { var theme = Theme.of(context); @@ -47,9 +54,10 @@ class Indicator extends StatelessWidget { return indicatorBuilder!.call(context, controller, index, count); case IndicatorMode.dot: return DotsIndicator( + dotSize: dotSize, + dotSpacing: dotSpacing, controller: controller, - color: theme.colorScheme.primary, - dotcolor: theme.colorScheme.secondary, + color: theme.colorScheme.secondary, itemCount: count, onPageSelected: (int page) { unawaited( @@ -153,16 +161,15 @@ class DotsIndicator extends AnimatedWidget { const DotsIndicator({ required this.controller, this.color = Colors.white, - this.dotcolor = Colors.green, this.itemCount, this.onPageSelected, + this.dotSize = 8.0, + this.dotSpacing = 24.0, super.key, }) : super( listenable: controller, ); - /// The PageController that this DotsIndicator is representing. - final Color? dotcolor; final PageController controller; /// The number of items managed by the PageController @@ -177,47 +184,31 @@ class DotsIndicator extends AnimatedWidget { final Color color; // The base size of the dots - static const double _kDotSize = 4.0; + final double dotSize; + final double dotSpacing; - // The increase in the size of the selected dot - static const double _kMaxZoom = 2.0; - - // The distance between the center of each dot - static const double _kDotSpacing = 12.0; - - Widget _buildDot(int index) { - var selectedness = Curves.easeOut.transform( - max( - 0.0, - 1.0 - - ((controller.page ?? controller.initialPage).round() - index).abs(), - ), - ); - var zoom = 1.0 + (_kMaxZoom - 1.0) * selectedness; - - return SizedBox( - width: _kDotSpacing, - child: Center( - child: Material( - color: (((controller.page ?? controller.initialPage).round()) == index - ? color - : color.withAlpha(125)), - type: MaterialType.circle, - child: Container( - decoration: BoxDecoration( - shape: BoxShape.circle, - border: Border.all(width: 2, color: dotcolor!), - ), - width: _kDotSize * 2 * zoom, - height: _kDotSize * 2 * zoom, - child: InkWell( - onTap: () => onPageSelected!.call(index), + Widget _buildDot(int index) => SizedBox( + width: dotSpacing, + child: Center( + child: Material( + color: + (((controller.page ?? controller.initialPage).round()) == index + ? color + : color.withAlpha(125)), + type: MaterialType.circle, + child: Container( + decoration: const BoxDecoration( + shape: BoxShape.circle, + ), + width: dotSize, + height: dotSize, + child: InkWell( + onTap: () => onPageSelected!.call(index), + ), ), ), ), - ), - ); - } + ); @override Widget build(BuildContext context) => Row( diff --git a/packages/flutter_introduction_widget/pubspec.yaml b/packages/flutter_introduction_widget/pubspec.yaml index 41315ca..04cded5 100644 --- a/packages/flutter_introduction_widget/pubspec.yaml +++ b/packages/flutter_introduction_widget/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_introduction_widget description: Flutter Introduction Widget for showing a list of introduction pages on a single scrollable page or horizontal pageview -version: 3.0.0 +version: 3.1.0 homepage: https://github.com/Iconica-Development/flutter_introduction_widget environment: diff --git a/pubspec.yaml b/pubspec.yaml index b691982..ae69ff2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: flutter_introduction_workspace -version: 3.0.0 +version: 3.1.0 environment: sdk: '>=3.1.0 <4.0.0'