Compare commits

..

No commits in common. "master" and "3.0.0" have entirely different histories.

37 changed files with 359 additions and 407 deletions

5
.gitignore vendored
View file

@ -31,6 +31,7 @@ build/
.metadata .metadata
pubspec.lock pubspec.lock
pubspec_overrides.yaml pubspec_overrides.yaml
@ -40,7 +41,3 @@ example/web
example/android example/android
example/linux example/linux
example/macos example/macos
# FVM Version Cache
.fvm/
.fvmrc

View file

@ -1,19 +1,3 @@
## 5.0.0
* Changed color of indicators
* Changed default button text
## 4.0.0
* Added Buildcontext to the pages parameter.
* Added `dotColor` so the default can be changed.
* Changed the default `pages` to include theme.
## 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 ## 3.0.0
* Update default styling * Update default styling

View file

@ -1 +0,0 @@
../../CHANGELOG.md

View file

@ -1 +0,0 @@
../../LICENSE

View file

@ -1 +0,0 @@
../../README.md

View file

@ -38,7 +38,7 @@ class _MyHomePageState extends State<MyHomePage> {
Widget build(BuildContext context) => Scaffold( Widget build(BuildContext context) => Scaffold(
body: Introduction( body: Introduction(
options: IntroductionOptions( options: IntroductionOptions(
pages: (context) => [ pages: [
const IntroductionPage( const IntroductionPage(
title: Text('First page'), title: Text('First page'),
text: Text('Wow a page'), text: Text('Wow a page'),

View file

@ -56,9 +56,7 @@ class _IntroductionState extends State<Introduction> {
// ignore: discarded_futures // ignore: discarded_futures
future: _service.shouldShow(), future: _service.shouldShow(),
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.data == null || if (snapshot.data == null || snapshot.data!) {
snapshot.data! ||
widget.options.mode == IntroductionScreenMode.showAlways) {
return IntroductionScreen( return IntroductionScreen(
options: widget.options, options: widget.options,
onComplete: () async { onComplete: () async {

View file

@ -1,21 +1,25 @@
name: flutter_introduction name: flutter_introduction
description: Combined Package of Flutter Introduction Widget and Flutter Introduction Service description: Combined Package of Flutter Introduction Widget and Flutter Introduction Service
version: 5.0.0 version: 3.0.0
publish_to: https://forgejo.internal.iconica.nl/api/packages/internal/pub publish_to: none
environment: environment:
sdk: ">=3.0.0 <4.0.0" sdk: ">=2.18.0 <3.0.0"
flutter: ">=1.17.0" flutter: ">=1.17.0"
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
flutter_introduction_widget: flutter_introduction_widget:
hosted: https://forgejo.internal.iconica.nl/api/packages/internal/pub git:
version: "^5.0.0" url: https://github.com/Iconica-Development/flutter_introduction
ref: 3.0.0
path: packages/flutter_introduction_widget
flutter_introduction_service: flutter_introduction_service:
hosted: https://forgejo.internal.iconica.nl/api/packages/internal/pub git:
version: "^5.0.0" url: https://github.com/Iconica-Development/flutter_introduction
ref: 3.0.0
path: packages/flutter_introduction_service
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

View file

@ -1 +0,0 @@
../../CHANGELOG.md

View file

@ -1 +0,0 @@
../../LICENSE

View file

@ -115,7 +115,7 @@ class _IntroductionState extends State<IntroductionFirebase> {
snapshot.data is List<IntroductionPageData>) { snapshot.data is List<IntroductionPageData>) {
return IntroductionScreen( return IntroductionScreen(
options: widget.options.copyWith( options: widget.options.copyWith(
pages: (context) => snapshot.data!.map( pages: snapshot.data?.map(
(e) { (e) {
var title = e.title.isEmpty var title = e.title.isEmpty
? '' ? ''

View file

@ -1,7 +1,7 @@
name: flutter_introduction_firebase name: flutter_introduction_firebase
description: Flutter Introduction Page that uses firebase for the pages and some settings description: Flutter Introduction Page that uses firebase for the pages and some settings
version: 5.0.0 version: 3.0.0
publish_to: https://forgejo.internal.iconica.nl/api/packages/internal/pub publish_to: none
environment: environment:
sdk: ">=3.1.5 <4.0.0" sdk: ">=3.1.5 <4.0.0"
@ -9,15 +9,19 @@ environment:
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
cloud_firestore: "^4.12.2" cloud_firestore: ^4.12.2
cached_network_image: "^3.3.0" cached_network_image: ^3.3.0
flutter_introduction_widget: flutter_introduction_widget:
hosted: https://forgejo.internal.iconica.nl/api/packages/internal/pub git:
version: "^5.0.0" url: https://github.com/Iconica-Development/flutter_introduction
ref: 3.0.0
path: packages/flutter_introduction_widget
flutter_introduction_service: flutter_introduction_service:
hosted: https://forgejo.internal.iconica.nl/api/packages/internal/pub git:
version: "^5.0.0" url: https://github.com/Iconica-Development/flutter_introduction
ref: 3.0.0
path: packages/flutter_introduction_service
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

View file

@ -1 +0,0 @@
../../CHANGELOG.md

View file

@ -1 +0,0 @@
../../LICENSE

View file

@ -1 +0,0 @@
../../README.md

View file

@ -1,18 +1,19 @@
name: flutter_introduction_interface name: flutter_introduction_interface
description: A new Flutter package project. description: A new Flutter package project.
version: 5.0.0 version: 3.0.0
publish_to: https://forgejo.internal.iconica.nl/api/packages/internal/pub publish_to: none
environment: environment:
sdk: '>=3.0.0 <4.0.0' sdk: '>=2.18.0 <3.0.0'
flutter: ">=1.17.0" flutter: ">=1.17.0"
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
flutter_data_interface: flutter_data_interface:
hosted: https://forgejo.internal.iconica.nl/api/packages/internal/pub git:
version: "^1.0.0" url: https://github.com/Iconica-Development/flutter_data_interface.git
ref: 1.0.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

View file

@ -1 +0,0 @@
../../CHANGELOG.md

View file

@ -1 +0,0 @@
../../LICENSE

View file

@ -1 +0,0 @@
../../README.md

View file

@ -1,18 +1,20 @@
name: flutter_introduction_service name: flutter_introduction_service
description: A new Flutter package project. description: A new Flutter package project.
version: 5.0.0 version: 3.0.0
publish_to: https://forgejo.internal.iconica.nl/api/packages/internal/pub publish_to: none
environment: environment:
sdk: '>=3.0.0 <4.0.0' sdk: '>=2.18.0 <3.0.0'
flutter: ">=1.17.0" flutter: ">=1.17.0"
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
flutter_introduction_interface: flutter_introduction_interface:
hosted: https://forgejo.internal.iconica.nl/api/packages/internal/pub git:
version: "^5.0.0" url: https://github.com/Iconica-Development/flutter_introduction
ref: 3.0.0
path: packages/flutter_introduction_interface
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

View file

@ -1 +0,0 @@
../../CHANGELOG.md

View file

@ -1 +0,0 @@
../../LICENSE

View file

@ -1 +0,0 @@
../../README.md

View file

@ -1,19 +1,21 @@
name: flutter_introduction_shared_preferences name: flutter_introduction_shared_preferences
description: A new Flutter package project. description: A new Flutter package project.
version: 5.0.0 version: 3.0.0
publish_to: https://forgejo.internal.iconica.nl/api/packages/internal/pub publish_to: none
environment: environment:
sdk: '>=3.0.0 <4.0.0' sdk: '>=2.18.0 <3.0.0'
flutter: ">=1.17.0" flutter: ">=1.17.0"
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
flutter_introduction_interface: flutter_introduction_interface:
hosted: https://forgejo.internal.iconica.nl/api/packages/internal/pub git:
version: "^5.0.0" url: https://github.com/Iconica-Development/flutter_introduction
shared_preferences: "^2.2.0" ref: 3.0.0
path: packages/flutter_introduction_interface
shared_preferences: any
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

View file

@ -1 +0,0 @@
../../CHANGELOG.md

View file

@ -1 +0,0 @@
../../LICENSE

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

View file

@ -31,7 +31,7 @@ class MyApp extends StatelessWidget {
), ),
home: IntroductionScreen( home: IntroductionScreen(
options: IntroductionOptions( options: IntroductionOptions(
pages: (context) => [ pages: [
const IntroductionPage( const IntroductionPage(
title: Text('Basic Page'), title: Text('Basic Page'),
text: Text( text: Text(

View file

@ -1,85 +1,115 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_introduction_widget/flutter_introduction_widget.dart'; import 'package:flutter_introduction_widget/flutter_introduction_widget.dart';
List<IntroductionPage> defaultIntroductionPages(BuildContext context) { const List<IntroductionPage> defaultIntroductionPages = [
var theme = Theme.of(context); IntroductionPage(
return [ decoration: BoxDecoration(
IntroductionPage( color: Color(0xffFAF9F6),
title: Column( ),
children: [ title: Column(
const SizedBox(height: 50), children: [
Text( SizedBox(height: 100),
'welcome to iconinstagram', Text(
style: theme.textTheme.headlineLarge, 'welcome to iconinstagram',
style: TextStyle(
color: Color(0xff71C6D1),
fontSize: 24,
fontWeight: FontWeight.w700,
), ),
const SizedBox(height: 6),
],
),
graphic: const Image(
image: AssetImage(
'assets/first.png',
package: 'flutter_introduction_widget',
), ),
), SizedBox(height: 6),
text: Text( Text(
'Welcome to the world of Instagram, where creativity' 'Welcome to the world of Instagram, where creativity'
' knows no bounds and connections are made' ' knows no bounds and connections are made'
' through captivating visuals.', ' through captivating visuals.',
textAlign: TextAlign.center, style: TextStyle(
style: theme.textTheme.bodyMedium, fontSize: 16,
fontWeight: FontWeight.w400,
),
textAlign: TextAlign.center,
),
],
),
graphic: Image(
image: AssetImage(
'assets/first.png',
package: 'flutter_introduction_widget',
), ),
), ),
IntroductionPage( text: Text(''),
title: Column( ),
mainAxisAlignment: MainAxisAlignment.center, IntroductionPage(
children: [ decoration: BoxDecoration(
const SizedBox(height: 50), color: Color(0xffFAF9F6),
Text( ),
'discover iconinstagram', title: Column(
style: theme.textTheme.headlineLarge, mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(height: 100),
Text(
'discover iconinstagram',
style: TextStyle(
color: Color(0xff71C6D1),
fontSize: 24,
fontWeight: FontWeight.w700,
), ),
const SizedBox(height: 6),
],
),
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,
style: theme.textTheme.bodyMedium,
),
graphic: const Image(
image: AssetImage(
'assets/second.png',
package: 'flutter_introduction_widget',
), ),
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,
),
],
),
graphic: Image(
image: AssetImage(
'assets/second.png',
package: 'flutter_introduction_widget',
), ),
), ),
IntroductionPage( text: Text(''),
title: Column( ),
children: [ IntroductionPage(
const SizedBox(height: 50), decoration: BoxDecoration(
Text( color: Color(0xffFAF9F6),
'elevate your experience', ),
style: theme.textTheme.headlineLarge, title: Column(
children: [
SizedBox(height: 100),
Text(
'elevate your experience',
style: TextStyle(
color: Color(0xff71C6D1),
fontSize: 24,
fontWeight: FontWeight.w700,
), ),
const SizedBox(height: 6),
],
),
graphic: const Image(
image: AssetImage(
'assets/third.png',
package: 'flutter_introduction_widget',
), ),
), SizedBox(height: 6),
text: Text( Text(
'Whether promoting your business, or connecting' 'Whether promoting your business, or connecting'
' with friends and family, Instagram provides the' ' with friends and family, Instagram provides the'
' tools and platform to make your voice heard.', ' tools and platform to make your voice heard.',
textAlign: TextAlign.center, style: TextStyle(
style: theme.textTheme.bodyMedium, fontSize: 16,
fontWeight: FontWeight.w400,
),
textAlign: TextAlign.center,
),
],
),
graphic: Image(
image: AssetImage(
'assets/third.png',
package: 'flutter_introduction_widget',
), ),
), ),
]; text: Text(''),
} ),
];

View file

@ -63,7 +63,7 @@ class IntroductionOptions {
this.introductionButtonTextstyles = const IntroductionButtonTextstyles(), this.introductionButtonTextstyles = const IntroductionButtonTextstyles(),
this.indicatorMode = IndicatorMode.dot, this.indicatorMode = IndicatorMode.dot,
this.indicatorBuilder, this.indicatorBuilder,
this.layoutStyle = IntroductionLayoutStyle.imageBottom, this.layoutStyle = IntroductionLayoutStyle.imageCenter,
this.pages = defaultIntroductionPages, this.pages = defaultIntroductionPages,
this.buttonMode = IntroductionScreenButtonMode.text, this.buttonMode = IntroductionScreenButtonMode.text,
this.tapEnabled = false, this.tapEnabled = false,
@ -73,9 +73,6 @@ class IntroductionOptions {
this.skippable = false, this.skippable = false,
this.buttonBuilder, this.buttonBuilder,
this.controlMode = IntroductionControlMode.previousNextButton, this.controlMode = IntroductionControlMode.previousNextButton,
this.dotSize = 12,
this.dotSpacing = 24,
this.dotColor,
}) : assert( }) : assert(
!(identical(indicatorMode, IndicatorMode.custom) && !(identical(indicatorMode, IndicatorMode.custom) &&
indicatorBuilder == null), indicatorBuilder == null),
@ -96,7 +93,7 @@ class IntroductionOptions {
/// List of introduction pages to set the text, icons or images for the /// List of introduction pages to set the text, icons or images for the
/// introduction screens. /// introduction screens.
final List<IntroductionPage> Function(BuildContext context) pages; final List<IntroductionPage> pages;
/// Determines whether the user can tap the screen to go to the next /// Determines whether the user can tap the screen to go to the next
/// introduction screen. /// introduction screen.
@ -207,19 +204,9 @@ class IntroductionOptions {
/// - Finish /// - Finish
final IntroductionButtonTextstyles introductionButtonTextstyles; 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;
/// The color of the dots in the indicator. Default is the primary color of
/// the theme
final Color? dotColor;
IntroductionOptions copyWith({ IntroductionOptions copyWith({
IntroductionScreenMode? mode, IntroductionScreenMode? mode,
List<IntroductionPage> Function(BuildContext context)? pages, List<IntroductionPage>? pages,
bool? tapEnabled, bool? tapEnabled,
IntroductionScreenButtonMode? buttonMode, IntroductionScreenButtonMode? buttonMode,
IntroductionLayoutStyle? layoutStyle, IntroductionLayoutStyle? layoutStyle,
@ -261,10 +248,10 @@ class IntroductionOptions {
class IntroductionTranslations { class IntroductionTranslations {
const IntroductionTranslations({ const IntroductionTranslations({
this.skipButton = 'Skip', this.skipButton = 'skip',
this.nextButton = 'Next', this.nextButton = 'Next',
this.previousButton = 'Previous', this.previousButton = 'Previous',
this.finishButton = 'Get started', this.finishButton = 'Get Started',
}); });
final String skipButton; final String skipButton;
final String nextButton; final String nextButton;
@ -274,10 +261,22 @@ class IntroductionTranslations {
class IntroductionButtonTextstyles { class IntroductionButtonTextstyles {
const IntroductionButtonTextstyles({ const IntroductionButtonTextstyles({
this.skipButtonStyle, this.skipButtonStyle = const TextStyle(
this.nextButtonStyle, fontSize: 16,
this.previousButtonStyle, fontWeight: FontWeight.w500,
this.finishButtonStyle, ),
this.nextButtonStyle = const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
),
this.previousButtonStyle = const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
),
this.finishButtonStyle = const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
),
}); });
final TextStyle? skipButtonStyle; final TextStyle? skipButtonStyle;
final TextStyle? nextButtonStyle; final TextStyle? nextButtonStyle;

View file

@ -77,7 +77,7 @@ class _MultiPageIntroductionScreenState
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var pages = widget.options.pages.call(context); var pages = widget.options.pages;
var translations = widget.options.introductionTranslations; var translations = widget.options.introductionTranslations;
return Stack( return Stack(
children: [ children: [
@ -150,21 +150,15 @@ class _MultiPageIntroductionScreenState
AnimatedBuilder( AnimatedBuilder(
animation: _currentPage, animation: _currentPage,
builder: (context, _) => Indicator( builder: (context, _) => Indicator(
options: widget.options,
indicatorBuilder: widget.options.indicatorBuilder, indicatorBuilder: widget.options.indicatorBuilder,
mode: widget.options.indicatorMode, mode: widget.options.indicatorMode,
controller: _controller, controller: _controller,
count: pages.length, count: pages.length,
index: _currentPage.value, index: _currentPage.value,
dotSize: widget.options.dotSize,
dotSpacing: widget.options.dotSpacing,
), ),
), ),
Padding( Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.all(32),
vertical: 40,
horizontal: 20,
),
child: AnimatedBuilder( child: AnimatedBuilder(
animation: _controller, animation: _controller,
builder: (context, _) { builder: (context, _) {
@ -276,14 +270,14 @@ class ExplainerPage extends StatelessWidget {
title: Padding( title: Padding(
padding: const EdgeInsets.symmetric(horizontal: 32), padding: const EdgeInsets.symmetric(horizontal: 32),
child: DefaultTextStyle( child: DefaultTextStyle(
style: theme.textTheme.titleMedium!, style: theme.textTheme.displayMedium!,
child: page.title ?? Text('introduction.$index.title'), child: page.title ?? Text('introduction.$index.title'),
), ),
), ),
text: Padding( text: Padding(
padding: const EdgeInsets.symmetric(horizontal: 32), padding: const EdgeInsets.symmetric(horizontal: 32),
child: DefaultTextStyle( child: DefaultTextStyle(
style: theme.textTheme.bodyMedium!, style: theme.textTheme.bodyLarge!,
child: page.text ?? Text('introduction.$index.description'), child: page.text ?? Text('introduction.$index.description'),
), ),
), ),
@ -342,159 +336,120 @@ class IntroductionTwoButtons extends StatelessWidget {
var translations = options.introductionTranslations; var translations = options.introductionTranslations;
var showFinishButton = var showFinishButton =
options.buttonMode == IntroductionScreenButtonMode.singleFinish; options.buttonMode == IntroductionScreenButtonMode.singleFinish;
var theme = Theme.of(context);
return Row( return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
if (options.buttonMode == IntroductionScreenButtonMode.text) ...[ if (options.buttonMode == IntroductionScreenButtonMode.text) ...[
Flexible( if (previous) ...[
child: Padding( options.buttonBuilder?.call(
padding: const EdgeInsets.only(right: 6), context,
child: ConstrainedBox( _previous,
constraints: const BoxConstraints( Text(
maxWidth: 180, translations.previousButton,
), style: options
child: Opacity( .introductionButtonTextstyles.previousButtonStyle,
opacity: previous ? 1 : 0, ),
child: IgnorePointer( IntroductionButtonType.previous,
ignoring: !previous, ) ??
child: options.buttonBuilder?.call( InkWell(
context, onTap: _previous,
_previous, child: Container(
Text( width: 180,
translations.previousButton, decoration: BoxDecoration(
style: options.introductionButtonTextstyles borderRadius: BorderRadius.circular(20),
.previousButtonStyle ?? border: Border.all(
theme.textTheme.bodyMedium, color: const Color(
), 0xff979797,
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 ??
theme.textTheme.bodyMedium,
),
),
),
),
), ),
),
),
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) ...[ if (next) ...[
Flexible( options.buttonBuilder?.call(
child: Padding( context,
padding: const EdgeInsets.only(left: 6), _next,
child: ConstrainedBox( Text(
constraints: const BoxConstraints( translations.nextButton,
maxWidth: 180, style: options.introductionButtonTextstyles.nextButtonStyle,
), ),
child: options.buttonBuilder?.call( IntroductionButtonType.next,
context, ) ??
_next, InkWell(
Text( 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(
translations.nextButton, translations.nextButton,
style: options.introductionButtonTextstyles style: options
.nextButtonStyle ?? .introductionButtonTextstyles.nextButtonStyle,
theme.textTheme.bodyMedium,
),
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 ??
theme.textTheme.bodyMedium,
),
),
),
), ),
), ),
), ),
),
),
] else if (last) ...[
Flexible(
child: Padding(
padding: const EdgeInsets.only(left: 6),
child: ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: 180,
), ),
child: options.buttonBuilder?.call( ),
context, ] else if (last) ...[
() { options.buttonBuilder?.call(
onFinish?.call(); context,
}, () {
Text( onFinish?.call();
translations.finishButton, },
style: options.introductionButtonTextstyles Text(
.finishButtonStyle ?? translations.finishButton,
theme.textTheme.bodyMedium, style:
), options.introductionButtonTextstyles.finishButtonStyle,
IntroductionButtonType.finish, ),
) ?? IntroductionButtonType.finish,
InkWell( ) ??
onTap: () { InkWell(
onFinish?.call(); onTap: () {
}, onFinish?.call();
child: Container( },
decoration: BoxDecoration( child: Container(
borderRadius: BorderRadius.circular(20), width: 180,
border: Border.all( decoration: BoxDecoration(
color: const Color( borderRadius: BorderRadius.circular(20),
0xff979797, 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 ??
theme.textTheme.bodyMedium,
),
),
),
), ),
), ),
),
child: Center(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 2.0),
child: Text(
translations.finishButton,
style: options
.introductionButtonTextstyles.finishButtonStyle,
),
),
),
),
), ),
),
),
] else ...[ ] else ...[
const SizedBox.shrink(), const SizedBox.shrink(),
], ],
@ -508,53 +463,44 @@ class IntroductionTwoButtons extends StatelessWidget {
maintainState: true, maintainState: true,
maintainInteractivity: false, maintainInteractivity: false,
child: Align( child: Align(
child: Flexible( child: options.buttonBuilder?.call(
child: ConstrainedBox( context,
constraints: const BoxConstraints( () {
maxWidth: 180, onFinish?.call();
), },
child: options.buttonBuilder?.call( Text(
context, translations.finishButton,
() { style: options
onFinish?.call(); .introductionButtonTextstyles.finishButtonStyle,
}, ),
Text( IntroductionButtonType.finish,
translations.finishButton, ) ??
style: options.introductionButtonTextstyles InkWell(
.finishButtonStyle ?? onTap: () {
theme.textTheme.bodyMedium, onFinish?.call();
), },
IntroductionButtonType.finish, child: Container(
) ?? width: 180,
InkWell( decoration: BoxDecoration(
onTap: () { borderRadius: BorderRadius.circular(20),
onFinish?.call(); border: Border.all(
}, color: const Color(
child: Container( 0xff979797,
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 ??
theme.textTheme.bodyMedium,
),
),
), ),
), ),
), ),
), child: Center(
), child: Padding(
padding: const EdgeInsets.symmetric(vertical: 2.0),
child: Text(
translations.finishButton,
style: options.introductionButtonTextstyles
.finishButtonStyle,
),
),
),
),
),
), ),
), ),
), ),

View file

@ -24,7 +24,7 @@ class Background extends StatelessWidget {
var theme = Theme.of(context); var theme = Theme.of(context);
var background = this.background ?? var background = this.background ??
BoxDecoration( BoxDecoration(
color: theme.colorScheme.surface, color: theme.colorScheme.background,
); );
var size = MediaQuery.of(context).size; var size = MediaQuery.of(context).size;
return Container( return Container(

View file

@ -3,6 +3,7 @@
// SPDX-License-Identifier: BSD-3-Clause // SPDX-License-Identifier: BSD-3-Clause
import 'dart:async'; import 'dart:async';
import 'dart:math';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_introduction_widget/src/config/introduction.dart'; import 'package:flutter_introduction_widget/src/config/introduction.dart';
@ -15,9 +16,6 @@ class Indicator extends StatelessWidget {
required this.count, required this.count,
required this.index, required this.index,
required this.indicatorBuilder, required this.indicatorBuilder,
required this.dotSize,
required this.dotSpacing,
required this.options,
super.key, super.key,
}) : assert( }) : assert(
!(mode == IndicatorMode.custom && indicatorBuilder == null), !(mode == IndicatorMode.custom && indicatorBuilder == null),
@ -41,14 +39,6 @@ class Indicator extends StatelessWidget {
final Widget Function(BuildContext, PageController, int, int)? final Widget Function(BuildContext, PageController, int, int)?
indicatorBuilder; indicatorBuilder;
/// The size of the dots.
final double dotSize;
/// The distance between the center of each dot.
final double dotSpacing;
final IntroductionOptions options;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var theme = Theme.of(context); var theme = Theme.of(context);
@ -57,10 +47,9 @@ class Indicator extends StatelessWidget {
return indicatorBuilder!.call(context, controller, index, count); return indicatorBuilder!.call(context, controller, index, count);
case IndicatorMode.dot: case IndicatorMode.dot:
return DotsIndicator( return DotsIndicator(
dotSize: dotSize,
dotSpacing: dotSpacing,
controller: controller, controller: controller,
color: options.dotColor ?? theme.colorScheme.primary, color: theme.colorScheme.primary,
dotcolor: theme.colorScheme.secondary,
itemCount: count, itemCount: count,
onPageSelected: (int page) { onPageSelected: (int page) {
unawaited( unawaited(
@ -76,7 +65,7 @@ class Indicator extends StatelessWidget {
return DashIndicator( return DashIndicator(
color: theme.colorScheme.primary, color: theme.colorScheme.primary,
controller: controller, controller: controller,
selectedColor: options.dotColor ?? theme.colorScheme.primary, selectedColor: theme.colorScheme.primary,
itemCount: count, itemCount: count,
onPageSelected: (int page) { onPageSelected: (int page) {
unawaited( unawaited(
@ -164,15 +153,16 @@ class DotsIndicator extends AnimatedWidget {
const DotsIndicator({ const DotsIndicator({
required this.controller, required this.controller,
this.color = Colors.white, this.color = Colors.white,
this.dotcolor = Colors.green,
this.itemCount, this.itemCount,
this.onPageSelected, this.onPageSelected,
this.dotSize = 8.0,
this.dotSpacing = 24.0,
super.key, super.key,
}) : super( }) : super(
listenable: controller, listenable: controller,
); );
/// The PageController that this DotsIndicator is representing.
final Color? dotcolor;
final PageController controller; final PageController controller;
/// The number of items managed by the PageController /// The number of items managed by the PageController
@ -187,31 +177,47 @@ class DotsIndicator extends AnimatedWidget {
final Color color; final Color color;
// The base size of the dots // The base size of the dots
final double dotSize; static const double _kDotSize = 4.0;
final double dotSpacing;
Widget _buildDot(int index) => SizedBox( // The increase in the size of the selected dot
width: dotSpacing, static const double _kMaxZoom = 2.0;
child: Center(
child: Material( // The distance between the center of each dot
color: static const double _kDotSpacing = 12.0;
(((controller.page ?? controller.initialPage).round()) == index
? color Widget _buildDot(int index) {
: color.withAlpha(62)), var selectedness = Curves.easeOut.transform(
type: MaterialType.circle, max(
child: Container( 0.0,
decoration: const BoxDecoration( 1.0 -
shape: BoxShape.circle, ((controller.page ?? controller.initialPage).round() - index).abs(),
), ),
width: dotSize, );
height: dotSize, var zoom = 1.0 + (_kMaxZoom - 1.0) * selectedness;
child: InkWell(
onTap: () => onPageSelected!.call(index), 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),
), ),
), ),
), ),
); ),
);
}
@override @override
Widget build(BuildContext context) => Row( Widget build(BuildContext context) => Row(

View file

@ -1,12 +1,10 @@
name: flutter_introduction_widget name: flutter_introduction_widget
description: Flutter Introduction Widget for showing a list of introduction pages on a single scrollable page or horizontal pageview description: Flutter Introduction Widget for showing a list of introduction pages on a single scrollable page or horizontal pageview
version: 5.0.0 version: 3.0.0
homepage: https://github.com/Iconica-Development/flutter_introduction_widget homepage: https://github.com/Iconica-Development/flutter_introduction_widget
publish_to: https://forgejo.internal.iconica.nl/api/packages/internal/pub
environment: environment:
sdk: ">=3.0.0 <4.0.0" sdk: ">=2.18.0 <3.0.0"
flutter: ">=1.17.0" flutter: ">=1.17.0"
dependencies: dependencies:

View file

@ -1,10 +1,7 @@
name: flutter_introduction_workspace name: flutter_introduction_workspace
description: The use case level package using both the flutter_introduction_widget and the flutter_introduction_service combined version: 3.0.0
version: 5.0.0
publish_to: None
environment: environment:
sdk: '>=3.1.0 <4.0.0' sdk: '>=3.1.0 <4.0.0'
dev_dependencies: dev_dependencies:
melos: ">=3.0.1 <7.0.0" melos: ">=3.0.1 <5.0.0"