Skip to content

Onboarding Screen #670

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions assets/lottie1.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions assets/lottie2.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions assets/lottie3.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions assets/lottie4.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions lib/consts.dart
Original file line number Diff line number Diff line change
Expand Up @@ -481,3 +481,5 @@ const kMsgClearHistory =
const kMsgClearHistorySuccess = 'History cleared successfully';
const kMsgClearHistoryError = 'Error clearing history';
const kMsgShareError = "Unable to share";
// Onboarding
enum AnimationType { fadeIn, scale, none ,bounce}
4 changes: 3 additions & 1 deletion lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import 'providers/providers.dart';
import 'services/services.dart';
import 'consts.dart';
import 'app.dart';
import 'screens/onboarding_screen.dart';

void main() async {
WidgetsFlutterBinding.ensureInitialized();
bool onboardingCompleted = await getOnboardingStatus();
var settingsModel = await getSettingsFromSharedPrefs();
final initStatus = await initApp(
kIsDesktop,
Expand All @@ -28,7 +30,7 @@ void main() async {
(ref) => ThemeStateNotifier(settingsModel: settingsModel),
)
],
child: const DashApp(),
child: (kIsMobile && !onboardingCompleted)? MaterialApp(home: OnboardingScreen()):DashApp(),
),
);
}
Expand Down
77 changes: 77 additions & 0 deletions lib/screens/onboarding_screen.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import 'package:apidash/consts.dart';
import 'package:apidash/utils/onboarding_utils.dart';
import 'package:flutter/material.dart';
import 'package:introduction_screen/introduction_screen.dart';
import 'package:apidash/widgets/button_onboarding_skip.dart';


class OnboardingScreen extends StatefulWidget {
const OnboardingScreen({super.key});

@override
State<OnboardingScreen> createState() => _OnboardingScreenState();
}

class _OnboardingScreenState extends State<OnboardingScreen> {


@override
Widget build(BuildContext context) {
final pages = [
buildPageViewModel(
asset: 'assets/lottie1.json',
title: 'Welcome!',
body: 'Have the Best Experience on Working with APIs',
animationType: AnimationType.fadeIn,
),
buildPageViewModel(
asset: 'assets/lottie2.json',
title: 'Organize your work!',
body: ' API Dash efficiently stores history.\nEnhancing seamless task management.',
animationType: AnimationType.scale,
),
buildPageViewModel(
asset: 'assets/lottie3.json',
title: 'Seamless and fast',
body: 'API Dash is built to be lightweight.',
),
buildPageViewModel(
asset: 'assets/lottie4.json',
title: 'Get Started with API Dash',
body: 'Start Using Now!',
animationType: AnimationType.bounce,
),
];
return Scaffold(
body: Stack(
children: [
IntroductionScreen(
pages: pages,
onDone: () => onCompleted(context),
next: const Icon(Icons.arrow_forward, size: 24,color: Colors.blueAccent,),
done: const Text(
'Start',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold,color: Colors.blue),
),
showBackButton: true,
dotsDecorator:DotsDecorator(
size: const Size(10.0, 8.0),
activeSize: const Size(30.0, 8.0),
color: Colors.grey.shade400,
activeColor: Colors.blueAccent,
spacing: const EdgeInsets.symmetric(horizontal: 4),
activeShape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5.0),
),
) ,

back: const Icon(Icons.arrow_back, size: 24,color: Colors.blue,),
),
skipButton(context)
],
),
);

}
}

9 changes: 9 additions & 0 deletions lib/services/shared_preferences_services.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,12 @@ Future<void> clearSharedPrefs() async {
final prefs = await SharedPreferences.getInstance();
await prefs.remove(kSharedPrefSettingsKey);
}

Future<bool> getOnboardingStatus() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getBool('onboardingCompleted') ?? false;
}
Future setOnboardingStatus() async{
final prefs = await SharedPreferences.getInstance();
await prefs.setBool('onboardingCompleted', true);
}
73 changes: 73 additions & 0 deletions lib/utils/onboarding_utils.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import 'package:apidash/app.dart';
import 'package:apidash/consts.dart';
import 'package:apidash/services/shared_preferences_services.dart';
import 'package:flutter/material.dart';
import 'package:flutter_animate/flutter_animate.dart';
import 'package:introduction_screen/introduction_screen.dart';
import 'package:lottie/lottie.dart';

Widget _getAnimatedLottie(String asset, AnimationType animationType) {
Widget lottieAnimation = Lottie.asset(asset, width: 250, height: 250);

switch (animationType) {
case AnimationType.fadeIn:
return lottieAnimation.animate().fadeIn(duration: 800.ms);
case AnimationType.scale:
return lottieAnimation.animate().scale(duration: 800.ms);
case AnimationType.bounce:
return lottieAnimation.animate().moveY(begin: -100, end: 0, duration: 1000.ms).scaleXY(end: 1.1, duration: 700.ms).then().scaleXY(end: 1.0, duration: 600.ms);
default:
return lottieAnimation;
}
}
Widget _getAnimatedText(String text, {bool isTitle = false}) {
TextStyle textStyle = TextStyle(
fontSize: isTitle ? 24 : 16,
fontWeight: isTitle ? FontWeight.bold : FontWeight.normal,
color: isTitle ? Colors.black : Colors.black54,
);

return Text(text, style: textStyle).animate()
.fadeIn(duration: (isTitle ? 1 : 1).seconds)
.slideY(begin: isTitle ? -0.3 : 0.3, end: 0);
}


PageViewModel buildPageViewModel({
required String asset,
required String title,
required String body,
AnimationType animationType = AnimationType.none,
}) {
return PageViewModel(
titleWidget: _getAnimatedText(title, isTitle: true),
bodyWidget: _getAnimatedText(body),
image: Center(child: _getAnimatedLottie(asset, animationType)),
decoration: const PageDecoration(
pageColor: Colors.white,
imagePadding: EdgeInsets.only(top: 40),
),
);
}



void onCompleted(BuildContext context) async {

Navigator.of(context).pushReplacement(
PageRouteBuilder(
transitionDuration: const Duration(milliseconds: 500),
pageBuilder: (context, animation, secondaryAnimation) => const DashApp(),
transitionsBuilder: (context, animation, secondaryAnimation, child) {
var tween = Tween(begin: const Offset(1.0, 0.0), end: Offset.zero)
.chain(CurveTween(curve: Curves.easeInOut));

return SlideTransition(
position: animation.drive(tween),
child: child,
);
},
),
);
await setOnboardingStatus();
}
21 changes: 21 additions & 0 deletions lib/widgets/button_onboarding_skip.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import 'package:apidash/utils/onboarding_utils.dart';
import 'package:flutter/material.dart';
Widget skipButton(BuildContext context) {
return Positioned(
top: 40,
right: 20,
child: TextButton(
onPressed: () {
onCompleted(context);
},
child: const Text(
'Skip',
style: TextStyle(
fontSize: 15,
color: Colors.blueAccent,
fontWeight: FontWeight.bold,
),
),
),
);
}
32 changes: 32 additions & 0 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.5.0"
dots_indicator:
dependency: transitive
description:
name: dots_indicator
sha256: c070af5058a084ba7b354df4b4c26c719595d70a3531eea6edd8af8716684ba3
url: "https://pub.dev"
source: hosted
version: "4.0.1"
equatable:
dependency: transitive
description:
Expand Down Expand Up @@ -515,6 +523,14 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_animate:
dependency: "direct main"
description:
name: flutter_animate
sha256: "7befe2d3252728afb77aecaaea1dec88a89d35b9b1d2eea6d04479e8af9117b5"
url: "https://pub.dev"
source: hosted
version: "4.5.2"
flutter_driver:
dependency: transitive
description: flutter
Expand Down Expand Up @@ -632,6 +648,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.6.1"
flutter_shaders:
dependency: transitive
description:
name: flutter_shaders
sha256: "34794acadd8275d971e02df03afee3dee0f98dbfb8c4837082ad0034f612a3e2"
url: "https://pub.dev"
source: hosted
version: "0.1.3"
flutter_svg:
dependency: "direct main"
description:
Expand Down Expand Up @@ -827,6 +851,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.19.0"
introduction_screen:
dependency: "direct main"
description:
name: introduction_screen
sha256: "02c123e074ee85b0ad0a8d3cd990f1eae78d5cfb2ac4588ad3703ac2a07fb5b0"
url: "https://pub.dev"
source: hosted
version: "3.1.17"
io:
dependency: transitive
description:
Expand Down
2 changes: 2 additions & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ environment:
dependencies:
flutter:
sdk: flutter
introduction_screen: ^3.1.8
flutter_animate: ^4.5.0
apidash_core:
path: packages/apidash_core
apidash_design_system:
Expand Down